Các phương pháp để bảo mật ứng dụng NodeJS – Phần 1


1068

Lời mở đầu

Mọi người đều đồng ý rằng bảo mật là rất quan trọng và với sự gia tăng các cuộc tấn công mạng trong thời gian gần đây, các tổ chức đang đầu tư về bảo mật ứng dụng. Trong bài viết này, chúng ta hãy nói về việc bảo mật một ứng dụng web được xây dựng trong NodeJS.

LƯU Ý: Các khái niệm bảo mật được thảo luận ở đây là ngôn ngữ hoặc framework bất khả tri. Ở chúng ta sẽ xem cách thực hiện các hoạt động này trong các ứng dụng web NodeJS.

Sử dụng SSL/TLS để liên lạc

Luôn luôn là một phương pháp hay để gửi dữ liệu của bạn qua HTTPS thay vì HTTP và đó là điều bắt buộc nếu ứng dụng của bạn truyền dữ liệu bí mật.

Mã hóa dữ liệu được truyền giữa máy khách và máy chủ giúp giảm thiểu một số cuộc tấn công như tấn công man-in-the-middle (MITM), nghe trộm, v.v. Hãy xem cách thiết lập TLS / SSL trong Express 4.x:

Trước tiên hãy tạo chứng chỉ tự ký:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365

Điều này tạo ra một chứng chỉ tự ký có giá trị trong 365 ngày.

LƯU Ý: Chứng chỉ tự ký không phải là lý tưởng cho production . Đối với production, bạn nên lấy chứng chỉ từ Cơ quan cấp chứng chỉ (CA).

Tiếp theo, bật HTTPS trên Express. Ngoài ra, chuyển hướng tất cả traffic HTTP sang HTTPS:

const fs = require('fs');
const https = require('https');
const express = require('express');const NODE_ENV = process.env.NODE_ENV || 'development';
const PORT = process.env.PORT || 3443;
const app = express();https.createServer({
  key: fs.readFileSync('/path/to/key.pem'),
  cert: fs.readFileSync('/path/to/cert.pem')
}, app).listen(PORT);// Redirect http requests to use https in production
if (NODE_ENV === 'production') {
  app.use((req, res, next) => {
    if (req.header('x-forwarded-proto') !== 'https') {
      res.redirect(`https://${req.header('host')}${req.url}`);
    } else {
      next();
    }
  });
}

Sử dụng header security

Strict-Transport-Security: 

Bảo mật truyền tải nghiêm ngặt HTTP (HTTP Strict Transport Security, viết tắt: HSTS) nếu được đặt trong header phản hồi, sẽ cho trình duyệt biết rằng nó chỉ nên giao tiếp bằng HTTPS thay vì HTTP trong khi giao tiếp với domain được chỉ định.

Cú pháp:

Strict-Transport-Security: max-age=<expire-time>

Ở đây, max-age là thời gian (tính bằng giây) mà trình duyệt nên nhớ rằng trang web này chỉ được truy cập bằng HTTPS.

Ví dụ từ facebook.com:

strict-transport-security:max-age=15552000;

X-Frame-Options: 

Header response HTTP này có thể được sử dụng để cho biết liệu một trình duyệt có được phép hiển thị một trang trong <frame>, <iframe> hoặc <object> hay không. Các trang web có thể sử dụng điều này để tránh các cuộc tấn công bằng cách nhấp chuột, bằng cách đảm bảo rằng nội dung của họ không được nhúng vào các trang web khác.

Cú pháp:

X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
X-Frame-Options: ALLOW-FROM https://siteutrust.com/

X-XSS-Protection: 

Header response HTTP này cho phép bộ lọc XSS tích hợp trong các trình duyệt hiện đại.

Ví dụ:

X-XSS-Protection: 1

X-Content-Type-Options: 

Header reponse HTTP này là một điểm đánh dấu được máy chủ sử dụng để chỉ ra rằng các loại MIME. Điều này được quảng cáo trong header Content-Type không được thay đổi và tuân theo. Điều này ngăn chặn các cuộc tấn công đánh hơi kiểu MIME.

Cú pháp:

X-Content-Type-Options: nosniff

Content-Security-Policy: 

Ngăn chặn một loạt các cuộc tấn công bao gồm cả tấn công Cross Site Scripting (XSS).

Cú pháp:

Content-Security-Policy: policy

Để có giải thích chi tiết về CSP, hãy truy cập liên kết này.

To set these headers in NodeJS, use the helmet npm package:

Để set các header này trong NodeJS, hãy sử dụng package npm helmet:

const express = require('express');
const helmet = require('helmet');
const app = express();
app.use(helmet())

This sets all the necessary headers in response.

Điều này set tất cả các header cần thiết trong response

Để set header riêng lẻ:

app.use(helmet({
  frameguard: {
    action: 'deny'
  }
}));

Để có danh sách đầy đủ các tiêu đề bảo mật cần được đặt trong ứng dụng web, hãy xem OWASP Secure Headers Project

NOTE: In some web servers, the security headers can be set in the server configuration file itself. For example, in nginx server, we can set the above headers in nginx.conf as shown below:

LƯU Ý: Trong một số server web, bảo mật header có thể được set trong chính tệp config server. Ví dụ, trong server nginx, chúng ta có thể set các header trên trong nginx.conf như hình dưới đây:

add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection 1;
add_header Content-Security-Policy "default-src 'self'";

Ngăn chặn các cuộc tấn công CSRF

Cross site request forgery (CSRF), còn được gọi là XSRF, Sea Surf hoặc Session Riding, là một vectơ tấn công đánh lừa trình duyệt web thực hiện một hành động không mong muốn trong ứng dụng mà người dùng đã đăng nhập. Các cuộc tấn công CSRF đặc biệt nhắm vào các yêu cầu thay đổi trạng thái và có thể buộc nạn nhân chuyển tiền, thay đổi email / mật khẩu, v.v.

CSRF thường được tiến hành bằng những kỹ thuật mạng xã hội, chẳng hạn như email hoặc liên kết đánh lừa nạn nhân. Và gửi request đến server thay mặt kẻ tấn công. Server không có cách nào để phân biệt một request giả mạo với một yêu cầu chính hãng.

Trong NodeJS, để ngăn chặn cuộc tấn công CSRF, chúng ta thường sử dụng m csurf express:

const cookieParser = require('cookie-parser');
const csrf = require('csurf');
const bodyParser = require('body-parser');
const express = require('express');const csrfProtection = csrf({ cookie: true });
const parseForm = bodyParser.urlencoded({ extended: false });
// create express app
const app = express();
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser());
app.get('/form', csrfProtection, (req, res) => {
  // pass the csrfToken to the view
  res.render('send', { csrfToken: req.csrfToken() });
});

In the view use the CSRF token passed:

Trong chế độ view, sử dụng token CSRF như sau:

<form action="/process" method="POST">
  <input type="hidden" name="csrf_token" value="{{csrfToken}}">
  Enter amount: <input type="number" name="amount">
  <button type="submit">Submit</button>
</form>

Ngăn chặn các cuộc tấn công XSS

Các cuộc tấn công Cross-Site Scripting (XSS) là một kiểu injection. Trong đó các đoạn code độc hại được đưa vào các trang web lành tính và đáng tin cậy.

Kẻ tấn công có thể sử dụng XSS để gửi một tập lệnh độc hại đến một người dùng không nghi ngờ. Trình duyệt của người dùng cuối không có cách nào để biết rằng tập lệnh không đáng được tin cậy và sẽ thực thi tập lệnh.

Bởi vì nó cho rằng tập lệnh đến từ một nguồn đáng tin cậy, tập lệnh độc hại có thể truy cập bất kỳ cookie, token hoặc thông tin nhạy cảm nào khác được trình duyệt lưu giữ và sử dụng với trang web đó. Các đoạn code này thậm chí có thể viết lại nội dung của trang HTML.

Quy tắc ngón tay cái để ngăn chặn loại tấn công này là luôn xác thực và làm sạch dữ liệu người dùng trước khi xử lý hoặc lưu trữ trong cơ sở dữ liệu. Không bao giờ tin tưởng dữ liệu đến từ người dùng.

Việc xác thực phải được thực hiện ở phía máy chủ. Vì quá trình xác thực phía máy khách có thể dễ dàng bị bỏ qua bằng cách sử dụng các công cụ như Burp Suite, TamperData, v.v.

Cách phổ biến để xác thực và làm sạch dữ liệu người dùng là sử dụng một thư viện như validator.js.

Ví dụ: Để xác thực một email

import validator from 'validator';if(validator.isEmail('foo@bar.com')) {
  // Process email or store in DB
}

Thư viện này cung cấp một số trình xác thực và lọc input của người dùng.

Các thư viện hữu ích khác bao gồm DOMPurifyxss-filter.

Dưới đây là một ví dụ để lọc input của người dùng bằng xss-filter:

const express = require('express');
const app = express();
const xssFilters = require('xss-filters');app.get('/', (req, res) => {
  let firstname = req.query.firstname; //an untrusted input
  res.send('<h1> Hello, '
    + xssFilters.inHTMLData(firstname)
    + '!</h1>');
});app.listen(3000);

Kết luận

Qua phần 1 về bảo mật web NodeJS, bạn có thể tránh được những tấn công thường thấy nhất. Chỉ với những thủ thuật này, giúp project không bị tấn công dẫn đến mất dữ liệu. Hãy đón xem phần 2 nhé ^^.

Tham khảo thêm về NodeJS tại đây : Hướng dẫn tạo Login Form React sử dụng Formik


Like it? Share with your friends!

1068