在 Node.js Web 开发中,缓存是提高性能的重要手段之一。但是,如果缓存被攻击者利用,就会出现缓存穿透的问题,导致系统性能下降,甚至崩溃。本文将介绍 Node.js Web 入口缓存穿透攻击的防范方法,为开发者提供指导意义。
什么是缓存穿透?
缓存穿透是指攻击者利用恶意请求绕过缓存直接访问数据库,导致系统性能下降,甚至崩溃。比如,攻击者通过构造不存在的 key,多次请求服务器,导致服务器每次都要查询数据库,从而造成缓存穿透。
为了防范缓存穿透攻击,我们可以采取以下措施:
1. 缓存空对象
当查询一个不存在的 key 时,我们可以将空对象缓存起来,避免多次查询数据库。比如,我们可以使用 Redis 缓存,将空对象的 key 缓存起来,设置过期时间,避免占用过多内存。
// javascriptcn.com 代码示例 const redis = require("redis"); const client = redis.createClient(); // 查询缓存中的 key function getFromCache(key) { return new Promise((resolve, reject) => { client.get(key, (err, result) => { if (err) { reject(err); } else { resolve(result); } }); }); } // 设置缓存空对象 function setEmptyCache(key) { client.set(key, "", "EX", 60 * 60 * 24); } // 查询数据库 function queryFromDB(key) { // TODO: 查询数据库 } // 获取数据 async function getData(key) { let data = await getFromCache(key); if (data) { return data; } else { data = await queryFromDB(key); if (data) { client.set(key, data, "EX", 60 * 60 * 24); return data; } else { setEmptyCache(key); return null; } } }
2. Bloom Filter 过滤器
Bloom Filter 是一种高效的数据结构,可以用来判断一个元素是否在集合中,同时可以减少不必要的数据库查询。我们可以将存在的 key 存储在 Bloom Filter 中,当查询一个不存在的 key 时,可以直接判断该 key 是否在 Bloom Filter 中,从而避免多次查询数据库。
// javascriptcn.com 代码示例 const bloomFilter = require("bloomfilter"); const filter = new bloomFilter.BloomFilter(32 * 256, 16); // 添加 key 到 Bloom Filter 中 function addKeyToFilter(key) { filter.add(key); } // 查询 Bloom Filter 是否包含 key function isInFilter(key) { return filter.test(key); } // 查询数据库 function queryFromDB(key) { // TODO: 查询数据库 } // 获取数据 async function getData(key) { if (isInFilter(key)) { let data = await queryFromDB(key); if (data) { addKeyToFilter(key); return data; } else { return null; } } else { return null; } }
3. 参数校验
我们可以对请求参数进行校验,避免非法请求绕过缓存直接访问数据库。比如,我们可以对请求参数进行正则匹配,只允许合法的参数请求。
// javascriptcn.com 代码示例 const app = require("express")(); // 参数校验中间件 function validateParams(req, res, next) { const { id } = req.query; const reg = /^\d+$/; if (!reg.test(id)) { res.status(400).send("Invalid parameter"); } else { next(); } } // 查询数据库 function queryFromDB(id) { // TODO: 查询数据库 } // 获取数据 app.get("/", validateParams, async (req, res) => { const { id } = req.query; const data = await queryFromDB(id); res.send(data); });
总结
通过缓存空对象、Bloom Filter 过滤器和参数校验等方式,我们可以有效地防范 Node.js Web 入口缓存穿透攻击,提高系统性能和安全性。开发者可以根据具体场景选择合适的防范方法,避免缓存穿透问题的出现。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/657955fbd2f5e1655d35c5af