Tin tức và phân tích của tất cả các thiết bị di động

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

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

Hiện tại, máy chủ phụ trợ và máy khách giao diện người dùng được triển khai trong 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ủ trong trình duyệt.

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

Tại sao yêu cầu nguồn gốc chéo bị chặn?

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

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

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 có yêu cầu cuộn tròn hoặc được gửi bằ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ự là về 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).

Hãy lấy một ví dụ, giả sử bất kỳ người dùng nào đã đăng nhập vào tài khoản PayPal của họ trong trình duyệt của họ. Nếu chúng tôi có thể gửi yêu cầu nhiều nguồn gốc tới paypal.com từ tập lệnh được tải trên một domain.com độc hại khác 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 https://malicious.com/transfer-money-to-attacker-account-from-user-paypal-account chuyển đổi nó thành một URL ngắn để ẩn URL thực. Khi người dùng nhấp vào liên kết độc hại, tập lệnh được tải trên miền malware.com sẽ gửi yêu cầu nguồn gốc chéo tới PayPal để chuyển số tiền của người dùng sang tài khoản PayPal của kẻ tấn công. Tất cả 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 hề hay biết.

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 gốc chéo) 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 để thông báo cho trình duyệt rằng yêu cầu nguồn gốc chéo đã được gửi từ các miền đáng tin cậy.
Máy chủ có bật tiêu đề CORS được sử dụng để tránh các yêu cầu nguồn gốc chéo bị trình duyệt chặn.

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

Bởi 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:

  • Một yêu cầu đơn giản
  • Hỏi đáp trước chuyến bay

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

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

. Nếu không, nó sẽ báo lỗi CORS.

  • Yêu cầu trước chuyến bay:
  • Tùy thuộc vào tham số yêu cầu tùy chỉnh từ yêu cầu gốc chéo, chẳng hạn như phương thức (PUT, DELETE), tiêu đề tùy chỉnh hoặc loại nội dung khác, v.v., trình duyệt sẽ quyết định gửi yêu cầu TÙY CHỌN preflight để kiểm tra xem yêu cầu thực tế có an toàn không để gửi hay không.

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

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

Làm cách 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 đăng nhập, 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 tham số yêu cầu.
  • Kiểm soát truy cập-Cho phép-Xuất xứ: Để chỉ định tên miền chính xác (https://app.geekflate.com, https://lab.newsblog.pl.com) hoặc ký tự đại diện
  • Access-Control-Allow-Methods: Để cho phép các phương thức HTTP (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS), chúng ta chỉ cần.
  • Access-Control-Allow-Headers: Chỉ cho phép các tiêu đề cụ thể (ủy quyền, csrf-token)
  • Kiểm soát truy cập-Cho phép-Thông tin xác thực: Boolean được sử dụng để cho phép thông tin xác thực chéo (cookie, tiêu đề ủy quyền).

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

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

Thực hiện theo hướng dẫn này để bật CORS trên Apache và Nginx.

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')
})

Kích hoạt CORS trong ExpressJS

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

npm install cors

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

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

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

Kiểm soát truy cập-Cho phép-Xuất xứ

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

Kích hoạt CORS cho tất cả các miền

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

Kích hoạt CORS cho một miền

Nếu bạn muốn cho phép CORS xuất xứ https://app.newsblog.pl.com và https://lab.newsblog.pl.com

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

Phương pháp kiểm soát truy cập

Để bật CORS cho tất cả các phương thức, hãy bỏ qua tùy chọn này trong mô-đun CORS trong ExpressJS. Nhưng để bao gồm 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']
}));

Kiểm soát truy cập-Cho phép-Tiêu đề

Được sử dụng để cho phép các tiêu đề không mặc định được 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
}));

Kiểm soát truy cập-Cho phép-Thông tin đăng nhập

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

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 
}));

Kiểm soát truy cập – tuổi tối đa

Yêu cầu trình duyệt lưu thông tin phản hồi trước vào bộ đệm trong một giây được chỉ định. Bỏ qua điều này nếu bạn không muốn lưu các câu trả lờ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 ban đầu được lưu trong bộ nhớ cache sẽ có sẵn trong trình duyệt của bạn trong 10 phú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 một ký tự đại diện

trong các Tiêu đề tiếp xúc sẽ không hiển thị tiêu đề Ủy quyền. Vì vậy, chúng ta cần phải phơi bày rõ ràng như dưới đây

Ở trên cũng sẽ tiết lộ tất cả các tiêu đề và tiêu đề ủy quyền.

  • Cookie HTTP là gì?
  • Cookie là một mẩu 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 trên mỗi yêu cầu.
  • Cookie có một thuộc tính có thể được xác định để làm cho cookie hoạt động khác với những gì chúng ta cần.
  • Tên Tên của cookie.
  • giá trị: dữ liệu cookie tương ứng với tên của cookie
  • Tên miền: Cookies sẽ chỉ được gửi đến tên miền đã xác định
  • Đường dẫn: Cookie chỉ được gửi theo đường dẫn tiền tố URL đã xác định. Giả sử chúng ta đã xác định một đường dẫn cookie như path=’admin/’. Cookie không được gửi cho URL https://newsblog.pl.com/expire/, nhưng được gửi với tiền tố URL https://newsblog.pl.com/admin/
  • Max-Age/Expires (số tính bằng giây): Thời điểm cookie hết hạn. Thời gian tồn tại của cookie làm cho cookie không hợp lệ sau một khoảng thời gian nhất định. [Strict, Lax, None]HTTPOnly(Boolean): Máy chủ phụ trợ có thể truy cập cookie HTTPOnly này, nhưng không thể truy cập tập lệnh phía máy khách khi đúng. Bảo mật (Boolean): Cookie được gửi bởi miền SSL/TLS chỉ khi true.samesite(string

): Được sử dụng để bật/hạn chế cookie được gửi như một phần của yêu cầu trên nhiều trang web. Để tìm hiểu thêm về cookie, hãy xem sameSite

MDN

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

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ộ lưu trữ phía máy khách, chẳng hạn như bộ nhớ cục bộ, cơ sở dữ liệu đượ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ử một trong các trang của bạn dễ bị tấn công XSS. Kẻ tấn công có thể lạm dụng mã thông báo người dùng được lưu trữ trong trình duyệt.

Cookie HTTPOnly chỉ được thiết lập/truy xuất 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ế truy cập cookie chỉ HTTP này. Vì vậy, cookie HTTPOnly không dễ bị tấn công XSS và an toàn hơn. Bởi vì nó chỉ có sẵn thông qua máy chủ.
  • Bật cookie HTTPOnly trên phụ trợ hỗ trợ CORS
  • Kích hoạt Cookies trong CORS yêu cầu cấu hình sau trong ứng dụng/máy chủ.
  • Đặt tiêu đề Kiểm soát truy cập-Cho phép-Thông tin xác thực thành true.

Kiểm soát truy cập-Cho phép-Xuất xứ và Kiểm soát truy cập-Cho phép-Tiêu đề 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 sameSite của cookie phải được đặt thành Không có.

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

Hãy xem mã mẫu đặt mã thông báo truy cập trong cookie HTTPOnly sau khi xác thực thông tin đăng nhập.

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

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.newsblog.pl.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.newsblog.pl.com/user', {
  credentials: 'include'
});

withCredentials cho yêu cầu Cross-Origin

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

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

axios.defaults.withCredentials = true

API XMLHttpRequest

Tải xuống API

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

Mục lục