什么是 CSRF 攻击?
跨站请求伪造(Cross-site request forgery,简称 CSRF)攻击是一种常见的 Web 攻击方式,它会利用用户在其他网站已经登录过的身份信息,来发起恶意请求。
举个例子,一个银行网站在用户登录后,会在浏览器中生成一个带有用户身份信息的 cookie。而如果在另一个恶意网站中,一个黑客诱导用户点击了一个链接,这个链接中包含一个请求银行网站的 URL,那么当用户点击了这个链接后,浏览器会携带着用户的 cookie 发起向银行网站的请求,因为浏览器无法区分来自哪个网站的请求,银行网站可能会认为这是正常的用户请求,从而执行这个请求。
因此,CSRF 攻击一般都是通过诱导用户在其他网站点击链接进行攻击。
CSRF 攻击的防御措施
1. 验证来源头(Referer)
其中一个简单的解决方案是利用 HTTP 在请求头里自带的来源头(Referer),该头告诉了服务器当前请求的来源地址。当服务器接收到请求时,可以通过规定的来源地址来判定当前的请求是否来自自己的站点。
该方案的缺点是:用户可以通过自己的浏览器或其他工具来修改 Referer 地址,从而绕开这种防御措施。
代码示例:
app.use(async (ctx, next) => { const ORIGIN = ctx.origin; const REFERER = ctx.get("Referer"); if (ORIGIN && REFERER && ORIGIN !== REFERER && !REFERER.includes(`${ORIGIN}/login`)) { ctx.throw(403, "请求不合法,禁止访问!"); } await next(); });
2. 验证 Token
一种更加可靠的解决方案是对每一个包含敏感操作的表单添加一个验证字段 Token,该 Token 和用户会话绑定,只有带有正确的 Token 才能提交表单,从而防止了 CSRF 攻击。
在 Koa 框架中,常见的 Token 方案有两种:Cookie 与 Session 方式,和 Token 字符串方式。
a. Cookie 与 Session 方式
在 Koa 中,Session 在默认情况下不会自动添加 csrfToken,需要手动添加,一般需要利用 Cookie 特性将 csrfToken 添加到客户端,然后在表单中再将该 Token 带回来:
-- -------------------- ---- ------- ----- ------- - ----------------------- -------- - ------ ------ ------- ----- ------ - - ---- -------------- ------- --------- ----------- ----- ---------- ----- --------- ----- ------- ----- -------- ------ ------ ------ --------- ---- -- ----------------------- ------ ------------- ----- ----- -- - ----- --------- - --------------------- -- -------------------------------------------------- --------------------- - ---------- ----- ------- --- ------------- ----- ----- -- - -- ----------- --- ------- - ----- ---- - ----- --------------- ----- --------- - --------------- -- ---------- --- ---------------------- - -------------- ---- --- --- ---------- -- ------ ---- ----------- - - ------- --- -------- -------------- - ------ --- ----------------- ------- -- - --- - --- ---- - --- ------------------ ----- -- - ---- -- ------ --- ----------------- -- -- - -------------------------- --- - ----- ----- - ------------ - --- -展开代码
通过上面的代码,每次在表单中提交的时候,都需要带上随机生成的 csrfToken 参数,服务端接收到 POST 请求时,需要对其进行校对。
b. Token 字符串方式
在这种方式下,Token 字符串是由服务端生成的,放到 meta 标签中,每次加载页面时,前端需要动态地读取该值,并将其插入到 form 表单中,以便在表单提交的时候一并带上。
服务端可以运用 Koa-jwt、jsonwebtoken 和 cookie 中间件等常用工具库来生成和校验 Token 字符串。
这种方案通过不再依赖 session 和 Cookie 的方式,提高了系统的安全性和灵活性,适用于 Restful 风格的 API,或者前后端分离项目。
代码示例:
-- -------------------- ---- ------- ----- --- - ------------------------ ----- ------ - ---- -------- ----- --------- - -- - -- - --- -------- -------------------- - ------ --- ----------------- ------- -- - ---------- ---- ------ -- ------- - --------- -- ----- ------ -- - -- ----- - ------ ------------ - --------------- --- --- - -------- --------------- - ----- ----- - --------------------------- --- - ----------------- -------- - ----- ----- - -------------- ---- --- --- ---------- -- ------ ---- ------------ - - ------------- ----- ----- -- - ------------- - ----- --------------------- ----- ------- --- ------------- ----- ----- -- - ----------------- - ------- ----------------- - - ------ ------ ----------- ------------ ----- ----------------- --------------------------- ------- ----------------------------------------------------------------------- ------- ------ ----- --------- -------------- ------ ----------- ---------------- ------ --------------- ---------------- ------ ------------- ---------------- ------------------------- ------- ------------------------- ------- -------- -------------------- -- - -- -- --------- -- ------------- -------- - --------------- -------------------------------------------- - --- -- --------- --------- -- --------------------------------- - ----------------------- ----- --- - --------- ----- ---- - ----------------------- ----------- ----- ------ -- - ------------------ --- --- --- --------- ------- ------- -- --- ------------- ----- ----- -- - -- ----------- --- ------- - ---------------- ----- ---- - ----- --------------- -------------------------- -------------- ---------------- -------- - - -------- ----- ------ -- - ----- ------- ---展开代码
总结
在 Koa 项目中防止 CSRF 攻击,需要对每个敏感操作新增 Token 验证机制。方案可以使用 cookie 与 session 方式或 Token 字符串方式,前者更适合非 Restful 风格的 Web 项目,具有快速、便捷的特点,后者则更适合 Restful 风格的 API 和前后端分离项目,具有灵活、安全的特点。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64eff035f6b2d6eab39d9b44