JavaScript giúp dễ dàng tra cứu các thuộc tính đối tượng một cách linh hoạt trong thời gian chạy. Cụ thể, các phương thức có thể được tra cứu theo tên và sau đó được gọi. Tuy nhiên, nếu tên phương thức do người dùng kiểm soát, kẻ tấn công có thể chọn một tên khiến ứng dụng gọi một phương thức không mong muốn, điều này có thể gây ra ngoại lệ thời gian chạy. Nếu ngoại lệ này không được xử lý, nó có thể được sử dụng để tấn công từ chối dịch vụ
Ví dụ: có thể không có phương thức của tên đã cho hoặc kết quả tra cứu có thể không phải là hàm. Trong cả hai trường hợp, cuộc gọi phương thức sẽ ném một TypeError
vào thời gian chạy
Một ví dụ khác, tinh tế hơn là kết quả tra cứu là một phương thức thư viện tiêu chuẩn từ Object.prototype
, mà hầu hết các đối tượng đều có trong chuỗi nguyên mẫu của chúng. Ví dụ về các phương pháp như vậy bao gồm valueOf
, hasOwnProperty
và __defineSetter__
. Nếu lệnh gọi phương thức chuyển sai số hoặc loại đối số cho các phương thức này, chúng sẽ đưa ra một ngoại lệ
Sự giới thiệu
Tốt nhất là tránh hoàn toàn tra cứu phương thức động liên quan đến các tên do người dùng kiểm soát, chẳng hạn bằng cách sử dụng một Map
thay vì một đối tượng đơn giản
Nếu không thể tránh tra cứu phương thức động, hãy xem xét đưa tên phương thức được phép vào danh sách trắng. Ít nhất, hãy kiểm tra xem phương thức đó có phải là thuộc tính riêng và không được kế thừa từ đối tượng nguyên mẫu không. Nếu đối tượng mà phương thức được tra cứu chứa các thuộc tính không phải là phương thức, bạn nên kiểm tra thêm xem kết quả tra cứu có phải là một hàm không. Ngay cả khi đối tượng chỉ chứa các phương thức, bạn vẫn nên thực hiện kiểm tra này trong trường hợp các thuộc tính khác được thêm vào đối tượng sau này
Thí dụ
Trong ví dụ sau, một thuộc tính tham số yêu cầu HTTP
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];0 được sử dụng để tra cứu động một hàm trong bản đồ
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];1, sau đó được gọi với tham số
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];2 làm đối số của nó
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];
Mục đích là để cho phép khách hàng gọi phương thức
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];3 hoặc
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];4, nhưng không kiểm tra xem
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];0 có thực sự là tên của một phương thức được lưu trữ trong
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];1. Ví dụ: nếu
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];0 là
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];8, thì
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];0 sẽ là
var express = require['express']; var app = express[]; var actions = new Map[]; actions.set["play", function play[data] { // ... }]; actions.set["pause", function pause[data] { // ... }]; app.get['/perform/:action/:payload', function[req, res] { if [actions.has[req.params.action]] { if [typeof actions.get[req.params.action] === 'function']{ let action = actions.get[req.params.action]; } // GOOD: `action` is either the `play` or the `pause` function from above res.end[action[req.params.payload]]; } else { res.end["Unsupported action."]; } }];0 và lệnh gọi sẽ dẫn đến lỗi thời gian chạy
Cách dễ nhất để ngăn chặn điều này là biến
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];1 thành
Map
và sử dụng var express = require['express']; var app = express[]; var actions = new Map[]; actions.set["play", function play[data] { // ... }]; actions.set["pause", function pause[data] { // ... }]; app.get['/perform/:action/:payload', function[req, res] { if [actions.has[req.params.action]] { if [typeof actions.get[req.params.action] === 'function']{ let action = actions.get[req.params.action]; } // GOOD: `action` is either the `play` or the `pause` function from above res.end[action[req.params.payload]]; } else { res.end["Unsupported action."]; } }];3 để kiểm tra xem tên phương thức có hợp lệ hay không trước khi tra cứu.
var express = require['express']; var app = express[]; var actions = new Map[]; actions.set["play", function play[data] { // ... }]; actions.set["pause", function pause[data] { // ... }]; app.get['/perform/:action/:payload', function[req, res] { if [actions.has[req.params.action]] { if [typeof actions.get[req.params.action] === 'function']{ let action = actions.get[req.params.action]; } // GOOD: `action` is either the `play` or the `pause` function from above res.end[action[req.params.payload]]; } else { res.end["Unsupported action."]; } }];
Nếu không thể biến
var express = require['express']; var app = express[]; var actions = { play[data] { // ... }, pause[data] { // ... } } app.get['/perform/:action/:payload', function[req, res] { let action = actions[req.params.action]; // BAD: `action` may not be a function res.end[action[req.params.payload]]; }];1 thành
Map
, thì nên thêm dấu kiểm hasOwnProperty
để xác thực tên phương thức