Làm cách nào để kích hoạt CORS với HTTPOnly Cookie để bảo mật mã thông báo?

Spread the love

Trong bài viết này, chúng tôi xem cách bật CORS (Chia sẻ tài nguyên chéo) với cookie HTTPOnly để bảo mật mã thông báo truy cập của chúng tôi.

Ngày nay, máy chủ phụ trợ và máy khách giao diện người dùng được triển khai trên các miền khác nhau. Do đó máy chủ phải kích hoạt CORS để cho phép máy khách giao tiếp với máy chủ trên các trình duyệt.

Ngoài ra, các máy chủ đang triển khai xác thực không trạng thái để có khả năng mở rộng tốt hơn. Các mã thông báo được lưu trữ và duy trì ở phía máy khách, nhưng không phải ở phía máy chủ như phiên. Để bảo mật, tốt hơn nên lưu trữ mã thông báo trong cookie HTTPOnly.

Mục lục

Tại sao các yêu cầu Cross-Origin bị chặn?

Giả sử rằng ứng dụng giao diện người dùng của chúng tôi được triển khai tại https://app.techpoe.com.com. Tập lệnh được tải trong https: //app.techpoe.com.com chỉ có thể yêu cầu các tài nguyên có cùng nguồn gốc.

Bất cứ khi nào chúng tôi cố gắng gửi một yêu cầu có nguồn gốc chéo đến một miền khác https://api.techpoe.com.com hoặc một cổng khác https://app.techpoe.com.com:3000 hoặc một lược đồ khác http://app.techpoe.com.com, yêu cầu nguồn gốc chéo sẽ bị trình duyệt chặn.

Nhưng tại sao cùng một yêu cầu bị trình duyệt chặn lại được gửi từ bất kỳ máy chủ phụ trợ nào bằng cách sử dụng yêu cầu curl hoặc được gửi bằng cách sử dụng các công cụ như người đưa thư mà không có bất kỳ sự cố CORS nào. Nó thực sự để bảo mật để bảo vệ người dùng khỏi các cuộc tấn công như CSRF (Cross-Site Request Forgery).

  Cách nhận thông báo dừng xe buýt hoặc tàu hỏa trên iPhone của bạn

Hãy lấy một ví dụ, giả sử nếu bất kỳ người dùng nào đăng nhập vào tài khoản PayPal của chính họ trong trình duyệt của họ. Nếu chúng tôi có thể gửi một yêu cầu có nguồn gốc chéo đến paypal.com từ một tập lệnh được tải trên một tên miền khác độc hại.com mà không có bất kỳ lỗi / chặn CORS nào giống như chúng tôi gửi yêu cầu cùng nguồn gốc.

Những kẻ tấn công có thể dễ dàng gửi trang độc hại của họ https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account bằng cách chuyển đổi nó thành URL ngắn để ẩn URL thực. Khi người dùng nhấp vào một liên kết độc hại, tập lệnh được tải trong miền độc hại.com sẽ gửi một yêu cầu có nguồn gốc chéo tới PayPal để chuyển số tiền của người dùng vào tài khoản PayPal của kẻ tấn công sẽ được thực thi. Tất cả những người dùng đã đăng nhập vào tài khoản PayPal của họ và nhấp vào liên kết độc hại này sẽ bị mất tiền. Bất kỳ ai cũng có thể dễ dàng ăn cắp tiền mà người dùng tài khoản PayPal không có kiến ​​thức.

Vì lý do trên, các trình duyệt chặn tất cả các yêu cầu nguồn gốc chéo.

CORS (Chia sẻ tài nguyên đa nguồn gốc) là gì?

CORS là một cơ chế bảo mật dựa trên tiêu đề được máy chủ sử dụng để yêu cầu trình duyệt gửi một yêu cầu có nguồn gốc chéo từ các miền đáng tin cậy.
Máy chủ được kích hoạt với tiêu đề CORS được sử dụng để tránh các yêu cầu có nguồn gốc chéo bị trình duyệt chặn.

CORS hoạt động như thế nào?

Vì máy chủ đã xác định miền đáng tin cậy của nó trong cấu hình CORS. Khi chúng tôi gửi yêu cầu đến máy chủ, phản hồi sẽ cho trình duyệt biết miền được yêu cầu có đáng tin cậy hay không trong tiêu đề của nó.

Có hai loại yêu cầu CORS:

  • Yêu cầu đơn giản
  • Yêu cầu Preflight

Yêu cầu đơn giản:

  • Trình duyệt sẽ gửi yêu cầu đến miền gốc chéo có origin (https://app.techpoe.com.com).
  • Máy chủ sẽ gửi lại phản hồi tương ứng với các phương thức được phép và nguồn gốc được phép.
  • Sau khi nhận được yêu cầu, trình duyệt sẽ kiểm tra giá trị tiêu đề gốc đã gửi (https://app.techpoe.com.com) và giá trị access-control-allow-origin đã nhận (https://app.techpoe.com.com) có giống nhau hay không ký tự đại diện

. Nếu không, nó sẽ xuất hiện một lỗi CORS.

  • Yêu cầu Preflight:
  • Tùy thuộc vào thông số yêu cầu tùy chỉnh từ yêu cầu gốc chéo như các phương thức (PUT, DELETE) hoặc tiêu đề tùy chỉnh hoặc loại nội dung khác nhau, v.v. hay không.

Sau khi nhận được phản hồi (mã trạng thái: 204, có nghĩa là không có nội dung), trình duyệt sẽ kiểm tra các thông số cho phép kiểm soát truy cập cho yêu cầu thực tế. Nếu các thông số yêu cầu được máy chủ cho phép. Yêu cầu thực tế có nguồn gốc chéo được gửi và nhận

Nếu access-control-allow-origin: *, thì phản hồi được phép cho tất cả các nguồn. Nhưng nó không an toàn trừ khi bạn cần.

Làm thế nào để kích hoạt CORS?

Để bật CORS cho bất kỳ miền nào, hãy bật tiêu đề CORS để cho phép nguồn gốc, phương thức, tiêu đề tùy chỉnh, thông tin xác thực, v.v.

  • Trình duyệt đọc tiêu đề CORS từ máy chủ và chỉ cho phép các yêu cầu thực tế từ máy khách sau khi xác minh các thông số yêu cầu.
  • Access-Control-Allow-Origin: Để chỉ định các miền chính xác (https://app.geekflate.com, https://lab.techpoe.com.com) hoặc ký tự đại diện
  • Access-Control-Allow-Method: Để cho phép các phương thức HTTP (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) mà chỉ chúng ta cần.
  • Access-Control-Allow-Headers: Để chỉ cho phép các Tiêu đề cụ thể (Ủy quyền, csrf-token)
  • Access-Control-Allow-Credentials: Giá trị Boolean được sử dụng để cho phép thông tin xác thực có nguồn gốc chéo (cookie, tiêu đề ủy quyền).
  Hướng dẫn nhanh về tác giả E-Learning để phát triển khóa học [+5 Tools]

Access-Control-Max-Age: Yêu cầu trình duyệt lưu vào bộ nhớ cache phản hồi preflight trong một thời gian.

Access-Control-Expose-Headers: Chỉ định các tiêu đề có thể truy cập bằng tập lệnh phía máy khách.

Để bật CORS trong apache và máy chủ web Nginx, hãy làm theo hướng dẫn này.

const express = require('express');
const app = express()

app.get('/users', function (req, res, next) {
  res.json({msg: 'user get'})
});

app.post('/users', function (req, res, next) {
    res.json({msg: 'user create'})
});

app.put('/users', function (req, res, next) {
    res.json({msg: 'User update'})
});

app.listen(80, function () {
  console.log('CORS-enabled web server listening on port 80')
})

Bật CORS trong ExpressJS

Hãy lấy một ví dụ về ứng dụng ExpressJS không có CORS:

npm install cors

Trong ví dụ trên, chúng tôi đã bật điểm cuối API người dùng cho các phương thức POST, PUT, GET nhưng không bật phương thức DELETE.

Để dễ dàng kích hoạt CORS trong ứng dụng ExpressJS, bạn có thể cài đặt các cors

app.use(cors({
    origin: '*'
}));

Access-Control-Allow-Origin

app.use(cors({
    origin: 'https://app.techpoe.com.com'
}));

Bật CORS cho tất cả miền

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ]
}));

Bật CORS cho một tên miền

Nếu bạn muốn cho phép CORS cho nguồn gốc https://app.techpoe.com.com và https://lab.techpoe.com.com

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST']
}));

Truy cập-Kiểm soát-Cho phép-Phương thức

Để bật CORS cho tất cả các phương pháp, hãy bỏ qua tùy chọn này trong mô-đun CORS trong ExpressJS. Nhưng để kích hoạt các phương thức cụ thể (GET, POST, PUT).

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token']
}));

Access-Control-Allow-Headers

Được sử dụng để cho phép các tiêu đề khác với tiêu đề mặc định gửi cùng với các yêu cầu thực tế.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true
}));

Access-Control-Allow-Credentials

Bỏ qua điều này nếu bạn không muốn yêu cầu trình duyệt cho phép thông tin đăng nhập theo yêu cầu ngay cả khi Thông tin đăng nhập được đặt thành true.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true,
    maxAge: 600 
}));

Access-Control-Max-Age

Để thân mật trình duyệt lưu thông tin phản hồi preflight vào bộ nhớ đệm trong một giây cụ thể. Bỏ qua điều này nếu bạn không muốn lưu phản hồi vào bộ nhớ cache.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true,
    maxAge: 600,
    exposedHeaders: ['Content-Range', 'X-Content-Range']
}));

Phản hồi preflight được lưu trong bộ nhớ cache sẽ có sẵn trong 10 phút trong trình duyệt.

app.use(cors({
    origin: [
        'https://app.geekflare.com',
        'https://lab.geekflare.com'
    ],
    methods: ['GET', 'PUT', 'POST'],
    allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'],
    credentials: true,
    maxAge: 600,
    exposedHeaders: ['*', 'Authorization', ]
}));

Access-Control-Expose-Headers

Nếu chúng ta đặt ký tự đại diện

trong contactHeaders, nó sẽ không hiển thị tiêu đề Authorization. Vì vậy, chúng tôi phải hiển thị rõ ràng như dưới đây

Ở trên cũng sẽ hiển thị tất cả các tiêu đề và tiêu đề Ủy quyền.

  • Cookie HTTP là gì?
  • Cookie là một phần dữ liệu nhỏ mà máy chủ sẽ gửi đến trình duyệt của khách hàng. Đối với các yêu cầu sau này, trình duyệt sẽ gửi tất cả các cookie liên quan đến cùng một miền theo mọi yêu cầu.
  • Cookie có thuộc tính của nó, có thể được xác định để làm cho một cookie hoạt động theo cách khác khi chúng ta cần.
  • Tên Tên của cookie.
  • value: dữ liệu của cookie tương ứng với cookie-name
  • Miền: cookie sẽ chỉ được gửi đến miền đã xác định
  • Đường dẫn: cookie chỉ được gửi sau đường dẫn tiền tố URL đã xác định. Giả sử nếu chúng ta đã xác định đường dẫn cookie của mình như path = ‘admin /’. Cookie không được gửi cho URL https://techpoe.com.com/expire/ nhưng được gửi với tiền tố URL https://techpoe.com.com/admin/
  • Max-Age / Expires (số tính bằng giây): Khi nào cookie sẽ hết hạn. Thời gian tồn tại của cookie làm cho cookie không hợp lệ sau thời gian quy định. [Strict, Lax, None]HTTPOnly (Boolean): Máy chủ phụ trợ có thể truy cập cookie HTTPOnly đó nhưng không phải tập lệnh phía máy khách khi đúng. Bảo mật (Boolean): Cookie chỉ được gửi qua miền SSL / TLS khi đúng.sameSite (chuỗi
  Microsoft's Outlook Spaces là gì? (hay còn gọi là Dự án Moca)

): Được sử dụng để bật / hạn chế cookie được gửi qua các yêu cầu trên nhiều trang web. Để biết thêm chi tiết về cookie cùng

MDN

. Nó chấp nhận ba tùy chọn nghiêm ngặt, lỏng lẻo, không. Giá trị bảo mật cookie được đặt thành true cho cấu hình cookie sameSite = Không có.

Tại sao lại sử dụng cookie HTTPOnly cho mã thông báo?

Lưu trữ mã thông báo truy cập được gửi từ máy chủ trong bộ nhớ phía máy khách như bộ nhớ cục bộ, DB được lập chỉ mục và cookie (HTTPOnly không được đặt thành true) dễ bị tấn công XSS hơn. Giả sử nếu bất kỳ trang nào của bạn yếu trước một cuộc tấn công XSS. Những kẻ tấn công có thể sử dụng sai mã thông báo của người dùng được lưu trữ trong trình duyệt.

Các cookie HTTPOnly chỉ được đặt / lấy bởi máy chủ / phụ trợ chứ không phải ở phía máy khách.

  • Tập lệnh phía máy khách bị hạn chế quyền truy cập cookie HTTPonly đó. Vì vậy, các cookie HTTPOnly không dễ bị tấn công XSS và an toàn hơn. Bởi vì nó chỉ có thể truy cập bởi máy chủ.
  • Bật cookie HTTPOnly trong chương trình phụ trợ được kích hoạt CORS
  • Bật Cookie trong CORS cần cấu hình bên dưới trong ứng dụng / máy chủ.
  • Đặt tiêu đề Access-Control-Allow-Credentials thành true.

Access-Control-Allow-Origin và Access-Control-Allow-Headers không được là ký tự đại diện

const express = require('express'); 
const app = express();
const cors = require('cors');

app.use(cors({ 
  origin: [ 
    'https://app.geekflare.com', 
    'https://lab.geekflare.com' 
  ], 
  methods: ['GET', 'PUT', 'POST'], 
  allowedHeaders: ['Content-Type', 'Authorization', 'x-csrf-token'], 
  credentials: true, 
  maxAge: 600, 
  exposedHeaders: ['*', 'Authorization' ] 
}));

app.post('/login', function (req, res, next) { 
  res.cookie('access_token', access_token, {
    expires: new Date(Date.now() + (3600 * 1000 * 24 * 180 * 1)), //second min hour days year
    secure: true, // set to true if your using https or samesite is none
    httpOnly: true, // backend only
    sameSite: 'none' // set to none for cross-request
  });

  res.json({ msg: 'Login Successfully', access_token });
});

app.listen(80, function () { 
  console.log('CORS-enabled web server listening on port 80') 
}); 

.

Thuộc tính cookie sameSite phải là Không có.

Để bật giá trị sameSite thành không, hãy đặt giá trị bảo mật thành true: Bật phụ trợ với chứng chỉ SSL / TLS để hoạt động trong tên miền.

Hãy xem mã ví dụ đặt mã thông báo truy cập trong cookie HTTPOnly sau khi kiểm tra thông tin đăng nhập.

Bạn có thể định cấu hình cookie CORS và HTTPOnly bằng cách triển khai bốn bước trên bằng ngôn ngữ phụ trợ và máy chủ web của bạn.

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.techpoe.com.com/user', true);
xhr.withCredentials = true;
xhr.send(null);

Bạn có thể làm theo hướng dẫn này cho apache và Nginx để kích hoạt CORS bằng cách làm theo các bước trên.

fetch('http://api.techpoe.com.com/user', {
  credentials: 'include'
});

withCredentials cho yêu cầu Cross-Origin

$.ajax({
   url: 'http://api.techpoe.com.com/user',
   xhrFields: {
      withCredentials: true
   }
});

Thông tin xác thực (Cookie, Ủy quyền) được gửi với yêu cầu cùng nguồn gốc theo mặc định. Đối với nguồn gốc chéo, chúng ta phải chỉ định withCredentials thành true.

axios.defaults.withCredentials = true

API XMLHttpRequest

API tìm nạp

JQuery AjaxAxiosSự kết luận Tôi hy vọng bài viết trên giúp bạn hiểu cách hoạt động của CORS và kích hoạt CORS cho các yêu cầu nguồn gốc chéo trong máy chủ. Tại sao lưu trữ cookie trong HTTPOnly lại an toàn và cách sử dụng Thông tin đăng nhập trong ứng dụng khách cho các yêu cầu có nguồn gốc chéo.

x