保护你的网站免受黑客攻击:深入解析XSS和CSRF漏洞
前言
- 随着网络技术的日益发展,网站安全问题变得日益突出。其中,XSS(跨站脚本攻击)和CSRF(跨站请求伪造)是两种常见而危险的攻击方式。本文将深入探讨XSS和CSRF攻击的实现方式以及针对这些攻击的防御策略。
XSS 攻击
- XSS (Cross Site Script,跨站脚本)攻击是一种利用网页漏洞,在用户的浏览器中执行恶意脚本的攻击方式。攻击者通过注入恶意脚本到网页中,使得用户的浏览器在解析网页时执行这些脚本,从而达到窃取用户信息、会话劫持、网站篡改等恶意目的。
分类
- XSS 主要可以分为三种类型:存储型(持久型)、反射型(非持久型)、基于DOM。
存储型(持久型)
- 攻击者将恶意脚本上传到目标网站的数据库中,当用户访问包含这些恶意脚本的页面时,浏览器会执行这些脚本。

案例:2015 年喜马拉雅存储型 XSS 攻击
- 由于用户设置专辑名称时,服务器对关键字过滤不严格,比如可以将专辑名称设置为一段 JavaScript 脚本:

- 当攻击者成功发布专辑后,其它用户访问该专辑时,则会将该恶意代码返回到用户页面,从而发起攻击:

反射型(非持久型)
- 攻击者将恶意脚本作为参数附加到URL中,当用户点击包含恶意脚本的链接时,服务器会将恶意脚本反射给用户的浏览器执行。
- 由于反射型 XSS 只是将用户的输入内容返回给浏览器,因此攻击者需要引诱用户点击构造的恶意链接,比如下面的案例:
- 先使用 Node 搭建一个简单的页面:
| var express = require('express'); |
| var router = express.Router(); |
| |
| |
| /* GET home page. */ |
| router.get('/', function(req, res, next) { |
| res.render('index', { title: 'Express',xss:req.query.xss }); |
| }); |
| |
| |
| module.exports = router; |
| |
| <!DOCTYPE html> |
| <html> |
| <head> |
| <title><%= title %></title> |
| <link rel='stylesheet' href='/stylesheets/style.css' /> |
| </head> |
| <body> |
| <h1><%= title %></h1> |
| <p>Welcome to <%= title %></p> |
| <div> |
| <%- xss %> |
| </div> |
| </body> |
| </html> |
- 当用户正常访问页面时:
http://localhost:3000/?xss=123

- 当用户点击攻击者构建的恶意链接时:
http://localhost:3000/?xss=alert('你被xss攻击了')

- 我们可以看到,反射型 XSS 并不会将恶意代码存储到页面服务器,而是使用引诱用户点击恶意链接的方式,页面服务器直接将恶意代码返回到用户页面,从而进行攻击。
基于 DOM
- 基于 DOM 的方式不涉及 Web 服务端,攻击者会使用各种方式篡改用户页面,达到获取用户数据进行攻击的目的,比如路由劫持,恶意软件等等。
防御策略
输入验证和过滤
- 对用户输入的数据进行严格的验证和过滤,防止恶意脚本的注入。
代码运行次数:3
| import re |
| |
| |
| def validate_input(input_text): |
| pattern = r'^[A-Za-z0-9\s,.!?]*$' |
| if re.match(pattern, input_text): |
| return True |
| else: |
| return False |
| |
| |
| user_comment = request.form.get('comment') |
| if validate_input(user_comment): |
| |
| else: |
| |
输出转码
- 在将用户输入的数据输出到网页时,对特殊字符进行转码,防止恶意脚本的执行。
代码运行次数:0
| # 将 < 转换为 <,将 > 转换为 > |
| # 示例:输出转码防止XSS攻击 |
| user_input = '<script>alert("XSS Attack!");</script>' |
| safe_output = escape(user_input) |
| print(safe_output) |
| # 输出结果:<script>alert("XSS Attack!");</script> |
使用HttpOnly标志
- 设置Cookie时使用HttpOnly标志,限制JavaScript对Cookie的访问,降低XSS攻击的风险。
代码运行次数:0
Cloud Studio 代码运行
| |
| response.set_cookie('session_id', value='xyz', httponly=True) |
内容安全策略(CSP)
- 内容安全策略(CSP)是一种通过设置HTTP头来限制网页加载资源的来源的安全机制。通过限制网页加载的资源来源,CSP可以有效防止恶意脚本的注入和执行,从而提高网站的安全性。
| 如:限制加载其他域下的资源文件,即使攻击者插入了一个 JavaScript 文件,这个文件也是无法被加载的; |
| 如:禁止向第三方域提交数据,这样用户数据也不会外泄; |
CSRF 攻击
- CSRF(Cross-site request forgery,跨站请求伪造)攻击是一种利用用户已登录的身份,在用户不知情的情况下,利用用户的权限发起恶意请求的攻击方式。攻击者通过诱导用户访问包含恶意请求的页面或者点击包含恶意请求的链接,来执行攻击。
同源策略(Same-Origin Policy)
- 同源策略(Same-Origin Policy)是一种浏览器安全机制,用于防止不同源之间的恶意行为。同源策略限制了一个网页文档或脚本如何与另一个源的资源进行交互。在Web安全中,源(origin)指的是一个网页的协议、主机和端口号的组合。如果两个URL的协议、主机和端口号完全相同,那么它们就是同源的。
- 同源策略其中一点体现在可以限制跨域请求,避免被限制请求,但是有些场景下请求是不跨域的,比如 img 资源、默认表单,我们来看看攻击者如何利用这些场景获取用户隐私信息进行攻击。
分类
- CSRF 攻击主要分为以下三种方式:自动发起Get请求、自动发起POST请求、引诱用户点击链接。
- 一般攻击者通过在页面构造恶意请求、攻击,引诱用户点击进行攻击。
自动发起Get请求
- 攻击者可以构造一个包含恶意请求的URL,并将其伪装成诱人的链接,当用户点击这个链接时,浏览器会自动发送GET请求,执行攻击者预设的操作。
| |
| <a href="http://victim-site.com/transfer?amount=10000&to=attacker-account">Click Me!</a> |
自动发起POST请求
- 攻击者可以通过构造一个自动提交的表单,并将表单隐藏在诱导用户点击的页面中。当用户访问这个页面时,表单会自动提交,发送POST请求,执行攻击者的恶意操作。
| |
| <form action="http://victim-site.com/transfer" method="post" id="csrf-form"> |
| <input type="hidden" name="amount" value="10000"> |
| <input type="hidden" name="to" value="attacker-account"> |
| </form> |
| |
| <script> |
| document.getElementById('csrf-form').submit(); |
| </script> |
防御策略
充分利用Cookie的SameSite属性
- 在 HTTP 响应头中,通过 set-cookie 字段设置 Cookie 时,可以带上 SameSite 选项,如下:
Set-Cookie: widget_session=abc123; SameSite=None; Secure

- SameSite 选项有 Strict、Lax 和 None 三个值:
Strict
- 最为严格的设置。如果Cookie的SameSite属性被设置为Strict,那么浏览器将完全禁止第三方Cookie的发送。这意味着,当你从一个网站访问另一个网站时,不会携带任何第三方Cookie。只有当你从目标网站直接请求资源时,才会发送相应的Cookie。
Lax
- 相对宽松一些。当Cookie的SameSite属性被设置为Lax时,在跨站情况下,从第三方网站的链接打开页面或者从第三方网站提交GET方式的表单都会携带Cookie。但如果是从第三方网站中使用POST方法,或者通过像img、iframe这样的标签加载URL时,则不会携带Cookie。
None
- 最宽松的设置。如果Cookie的SameSite属性设置为None,那么无论在何种情况下都会发送Cookie数据,即使是跨站请求也会携带Cookie。但需要注意的是,如果设置为None,必须同时设置Secure属性,即Cookie只能通过HTTPS协议发送,否则设置将无效。
- 我们可以结合实际情况,将一些 cookie 设置为 Strict、Lax ,从而减少 CSRF 的风险。
检查Referer头
- Referer头包含了当前请求的来源页面的URL,可以用来验证请求是否来自合法的来源。在服务器端,可以检查请求的Referer头,确保请求来自于期望的来源。但需要注意 Referer 的可信度。

使用CSRF Token
- CSRF Token是一个随机生成的字符串,用于验证请求是否来自合法用户。在每个敏感操作的请求中,都需要包含这个CSRF Token,并且服务器端需要验证该Token的有效性。
| <! DOCTYPE html> |
| <html> |
| <body> |
| <form action="http://victim-site.com/transfer" method="POST"> |
| <input type="hidden"" name=lcsrf-token"" value="nc98P987bcpncYhoadjoiydc9ajDl"> |
| <input type="text" name="user"> |
| <input type="text" name="number"> |
| <input type="submit"> |
| </form> |
| </body> |
| </html> |