在这里插入图片描述

Web安全是网络安全学习中非常重要的一个方向。很多初学者在学习漏洞时,容易陷入“记Payload、记工具、记命令”的误区,却忽略了漏洞产生的真正原因。

实际上,SQL注入、XSS、CSRF、SSRF、文件上传以及越权等漏洞虽然表现形式不同,但背后都有一个共同逻辑:不可信的数据进入了不应该进入的位置,或者用户拥有了不应该拥有的权限。

本文从HTTP请求开始,逐步分析常见Web安全问题,并结合Python、JavaScript等代码示例,帮助初学者建立比较系统的Web安全思维。


一、Web安全到底在研究什么?

Web安全简单来说,就是研究Web应用在开发、部署和运行过程中可能出现的安全问题,并通过安全测试和安全设计降低风险。

一个简单的网站,看起来只是:

浏览器
  ↓
输入网址
  ↓
打开网页

但真正的请求链路可能是:

浏览器
  ↓
DNS
  ↓
CDN
  ↓
WAF
  ↓
Web服务器
  ↓
应用程序
  ↓
数据库
  ↓
内部服务

任何一层出现配置错误或者代码问题,都可能影响整体安全。

因此,学习Web安全不能只盯着某一个漏洞。

更重要的是理解:

用户输入从哪里来?
 ↓
经过什么处理?
 ↓
最终去了哪里?
 ↓
谁有权限访问?
 ↓
系统有没有正确的安全边界?

二、为什么HTTP是Web安全的基础?

学习Web安全之前,最好先把HTTP弄明白。

例如一个普通GET请求:

GET /user?id=1001 HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Accept: text/html
Cookie: session=abcdef123456

这里至少需要理解:

  • 请求方法
  • URL
  • 请求头
  • Cookie
  • 参数

POST请求则可能是:

POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded

username=test&password=123456

安全测试时,经常需要观察:

请求方法
URL
参数
Cookie
Header
状态码
响应长度
响应内容
响应时间

例如:

GET /search?keyword=hello HTTP/1.1

这里的:

keyword=hello

就是一个值得分析的输入点。


三、漏洞分析最重要的思想:数据流

理解漏洞最简单的方法,就是分析数据流。

可以把很多漏洞抽象成:

用户输入
   ↓
应用处理
   ↓
危险操作

例如:

SQL注入

用户输入
   ↓
SQL字符串拼接
   ↓
数据库

XSS

用户输入
   ↓
HTML输出
   ↓
浏览器解析

命令执行

用户输入
   ↓
Shell命令
   ↓
操作系统

路径遍历

用户输入
   ↓
文件路径
   ↓
文件系统

所以漏洞挖掘真正要寻找的是:

用户可控的数据,是否进入了危险的处理流程?


四、SQL注入是什么?

SQL注入是最经典的Web漏洞之一。

假设存在下面的代码:

username = request.form["username"]

sql = (
    "SELECT * FROM users "
    "WHERE username = '" + username + "'"
)

cursor.execute(sql)

问题在于:

用户输入
   ↓
字符串拼接
   ↓
SQL语句
   ↓
数据库执行

也就是说,用户输入直接影响了SQL语句的结构。

这就是SQL注入产生的根本原因。


五、SQL注入应该如何修复?

最常见的方法之一就是参数化查询。

例如:

username = request.form["username"]

cursor.execute(
    "SELECT * FROM users WHERE username = ?",
    (username,)
)

此时:

SQL结构
+
用户数据

被明确区分。

相比之下,下面这种方式不推荐:

sql = "SELECT * FROM users WHERE id=" + user_id

更安全的写法:

cursor.execute(
    "SELECT * FROM users WHERE id = ?",
    (user_id,)
)

因此在开发Web应用时:

尽量使用参数化查询,不要通过字符串拼接构造SQL。


六、哪些参数值得重点关注?

在经过授权的安全测试环境中,可以重点观察:

id
uid
user_id
username
keyword
search
page
sort
order
category

例如:

GET /product?id=1001 HTTP/1.1

此时可以进一步分析:

id
 ↓
后台如何处理?
 ↓
是否进入数据库?
 ↓
是否进行类型校验?
 ↓
是否使用参数化查询?

需要注意:

出现数据库报错
≠
一定存在SQL注入

没有数据库报错
≠
一定不存在SQL注入

现代应用经常会统一处理异常。

因此真正的漏洞判断应该综合:

源码
日志
响应内容
状态码
业务行为

七、XSS是什么?

XSS的全称是:

Cross-Site Scripting

中文一般叫做:

跨站脚本攻击。

它的核心问题是:

应用程序把不可信输入当成了HTML或者脚本内容。

例如:

const value = new URLSearchParams(
    location.search
).get("keyword");

document.getElementById(
    "result"
).innerHTML = value;

问题就在:

innerHTML

浏览器会按照HTML内容解析它。

如果只是单纯展示文本,更推荐:

const value = new URLSearchParams(
    location.search
).get("keyword");

document.getElementById(
    "result"
).textContent = value;

区别非常简单:

innerHTML
↓
按照HTML解析

textContent
↓
按照普通文本处理

八、XSS常见类型

1. 反射型XSS

数据流通常是:

用户输入
 ↓
服务器
 ↓
响应
 ↓
浏览器

常见场景:

搜索
错误提示
参数回显
跳转页面

2. 存储型XSS

数据会先保存:

用户输入
 ↓
数据库
 ↓
页面读取
 ↓
浏览器

常见位置:

评论
留言
昵称
个人签名
文章标题

这种问题的影响范围往往更值得关注。


3. DOM型XSS

漏洞发生在浏览器端:

const content = location.hash.substring(1);

document.querySelector(
    "#output"
).innerHTML = content;

这类问题不一定需要服务器参与,因此前端代码安全也非常重要。


九、CSRF是什么?

CSRF:

Cross-Site Request Forgery

中文称为:

跨站请求伪造。

简单理解就是:

利用用户当前已经登录的身份,让浏览器执行一个用户没有主动发起的请求。

例如系统存在:

POST /change-email HTTP/1.1

email=test@example.com

如果服务端只依赖Cookie判断身份:

浏览器
 ↓
自动携带Cookie
 ↓
服务器

就需要考虑非预期请求的问题。


十、CSRF如何防御?

经典方案之一是:

CSRF Token。

例如:

import secrets

csrf_token = secrets.token_hex(32)

print(csrf_token)

页面:

<input
    type="hidden"
    name="csrf_token"
    value="RANDOM_TOKEN">

服务器进行验证:

token = request.form["csrf_token"]

if token != session["csrf_token"]:
    return "Invalid request", 403

除此之外,还可以结合:

SameSite Cookie
Origin检查
Referer检查
敏感操作二次认证

形成多层防护。


十一、文件上传为什么危险?

很多网站都有:

头像上传
图片上传
简历上传
附件上传
视频上传

错误示例:

filename = upload.filename

upload.save(
    "/var/www/uploads/" + filename
)

这里至少存在几个问题:

文件名可信吗?
文件内容可信吗?
文件类型可信吗?
文件大小有限制吗?
上传目录是否允许执行?

因此不能只检查文件扩展名。

可以先建立白名单:

ALLOWED_EXTENSIONS = {
    ".jpg",
    ".jpeg",
    ".png",
    ".gif"
}

然后进行后缀检查:

from pathlib import Path

filename = Path(upload.filename)

if filename.suffix.lower() not in ALLOWED_EXTENSIONS:
    raise ValueError(
        "unsupported file type"
    )

实际生产环境还应该增加:

MIME检测
文件头检测
文件内容检测
重新编码
随机文件名
大小限制
病毒扫描
存储隔离

十二、为什么上传目录不能直接执行脚本?

假设网站目录:

/var/www/html/

上传目录:

/var/www/html/uploads/

如果上传目录同时存在:

写入权限
+
脚本执行权限

那么一旦文件校验出现问题,影响可能进一步扩大。

更合理的结构:

/var/www/app/
    ├── src/
    ├── config/
    └── static/

/data/uploads/

让上传内容进入独立数据目录。

安全原则就是:

用户可以上传文件,不代表服务器应该执行这个文件。


十三、命令执行漏洞为什么危险?

来看一个简单例子:

import os

host = request.args.get("host")

os.system(
    "ping -c 1 " + host
)

程序本来的设计:

输入IP
 ↓
执行Ping
 ↓
返回结果

但是实际情况:

用户输入
 ↓
Shell命令
 ↓
操作系统

于是用户输入就进入了操作系统命令解释环境。


十四、如何降低命令执行风险?

可以使用参数数组:

import subprocess

host = request.args.get("host")

result = subprocess.run(
    ["ping", "-c", "1", host],
    capture_output=True,
    text=True,
    timeout=5
)

print(result.stdout)

同时可以增加IP格式验证:

import ipaddress

try:
    ipaddress.ip_address(host)
except ValueError:
    raise ValueError("Invalid IP address")

进一步还可以增加:

命令白名单
超时
资源限制
低权限账户
日志审计

十五、越权漏洞为什么很容易被忽略?

很多安全测试只关注:

SQL注入
XSS
文件上传
命令执行

却容易忽略越权。

例如:

GET /api/order?id=1001 HTTP/1.1

当前用户:

user_id = 1001

能够查询自己的订单。

但是:

GET /api/order?id=1002 HTTP/1.1

如果也能返回数据,那么可能存在:

用户A
 ↓
访问
 ↓
用户B订单

这就是典型的对象级授权问题。


十六、越权漏洞如何修复?

错误代码:

order = get_order(order_id)

return order

更安全的逻辑:

order = get_order(order_id)

if order.user_id != current_user.id:
    return "Forbidden", 403

return order

核心原则:

用户认证成功,不代表用户拥有所有资源访问权限。


十七、认证与授权有什么区别?

这是Web安全非常基础的概念。

Authentication:认证

回答:

你是谁?

例如:

用户名
密码
验证码
MFA
Token

Authorization:授权

回答:

你可以做什么?

例如:

普通用户
管理员
财务
审计员
开发人员

所以:

认证成功
≠
拥有全部权限

十八、SSRF是什么?

SSRF:

Server-Side Request Forgery

中文称:

服务端请求伪造。

常见业务场景:

用户输入URL
 ↓
服务器访问URL
 ↓
返回结果

例如:

import requests

url = request.args.get("url")

response = requests.get(
    url,
    timeout=5
)

return response.text

问题在于:

用户是否可以任意控制URL?

如果可以,就需要考虑服务器可能被诱导访问本不应该访问的内部资源。

因此生产环境应该进行:

URL解析
协议限制
IP校验
DNS校验
重定向控制
访问范围限制

十九、路径遍历是什么?

假设存在:

GET /download?file=manual.pdf

后台代码:

filename = request.args["file"]

path = "/data/files/" + filename

return send_file(path)

问题是:

filename

是否完全可信。

如果用户可以任意控制服务器读取路径,就可能出现文件访问范围突破。

一种安全思路是白名单:

FILES = {
    "manual": "/data/files/manual.pdf",
    "guide": "/data/files/guide.pdf"
}

key = request.args.get("name")

path = FILES.get(key)

if not path:
    return "Not Found", 404

return send_file(path)

这样客户端只能访问程序明确允许的资源。


二十、API安全为什么越来越重要?

现在很多Web应用已经从传统网页变成:

前端
 ↓
API
 ↓
微服务
 ↓
数据库

例如:

POST /api/v1/user/update
Content-Type: application/json

{
    "username": "test",
    "email": "test@example.com"
}

测试API的时候,不仅要看参数,还要看:

认证
授权
对象ID
敏感字段
速率限制
返回数据

二十一、API中的敏感字段问题

例如客户端发送:

{
    "username": "test",
    "email": "test@example.com",
    "role": "admin"
}

如果后端直接:

update_user(request.json)

就可能导致客户端控制本不应该修改的敏感字段。

更加合理的是字段白名单:

allowed_fields = {
    "username",
    "email"
}

data = {
    key: value
    for key, value in request.json.items()
    if key in allowed_fields
}

这样可以减少:

批量赋值
敏感字段修改
权限字段覆盖

等风险。


二十二、Burp Suite在Web安全学习中的作用

Burp Suite是Web安全学习中非常常见的工具。

它最核心的功能不是“一键扫描”,而是:

拦截
修改
重放
分析

例如:

GET /user?id=1001 HTTP/1.1
Host: example.com
Cookie: session=xxxx

可以从请求中分析:

方法
URL
Cookie
Header
参数

再结合响应:

状态码
长度
内容
时间

判断应用行为是否发生变化。

因此:

Burp Suite更适合作为HTTP分析工具,而不是单纯的扫描器。


二十三、为什么不能完全依赖扫描器?

自动化扫描很适合:

资产发现
批量检测
快速验证
初步筛选

但很多业务逻辑问题很难自动判断。

例如:

优惠券
订单
退款
积分
支付
审批
权限

这些功能需要安全人员理解:

业务流程
身份关系
权限边界
数据关系

所以更加合理的方式是:

人工理解业务
      ↓
工具辅助分析
      ↓
自动化检测
      ↓
人工确认
      ↓
形成报告

二十四、如何建立自己的Web安全测试清单?

资产层

[ ] 域名
[ ] 子域名
[ ] IP
[ ] 开放端口
[ ] Web服务
[ ] API

功能层

[ ] 登录
[ ] 注册
[ ] 搜索
[ ] 用户资料
[ ] 文件上传
[ ] 文件下载
[ ] 密码修改
[ ] 管理后台

漏洞层

[ ] SQL注入
[ ] XSS
[ ] CSRF
[ ] SSRF
[ ] 文件上传
[ ] 路径遍历
[ ] 命令执行
[ ] 越权

认证授权层

[ ] Session
[ ] JWT
[ ] MFA
[ ] 权限控制
[ ] 水平越权
[ ] 垂直越权

二十五、Python如何帮助安全自动化?

安全工作中经常需要处理:

大量URL
大量接口
大量参数
大量日志

Python非常适合做自动化。

例如:

from urllib.parse import urlparse, parse_qs

url = (
    "https://example.com/search"
    "?id=1001&keyword=test&redirect=/home"
)

parsed = urlparse(url)

params = parse_qs(
    parsed.query
)

for key, value in params.items():
    print(
        f"{key} -> {value}"
    )

输出:

id -> ['1001']
keyword -> ['test']
redirect -> ['/home']

后续可以继续加入:

参数分类
风险标记
测试记录
报告生成

二十六、安全人员真正应该培养什么能力?

很多人认为网络安全就是:

会Nmap
会Burp
会Kali
会扫描

实际上远远不够。

真正重要的是:

理解协议
理解代码
理解数据库
理解系统
理解权限
理解业务
理解数据流

例如看到:

sql = "SELECT * FROM user WHERE id=" + user_id

能够第一时间想到:

用户输入
 ↓
字符串拼接
 ↓
SQL

再看到:

element.innerHTML = value

应该想到:

用户输入
 ↓
HTML
 ↓
浏览器解析

这就是漏洞思维。


二十七、推荐的Web安全学习路线

如果准备系统学习Web安全,可以按照:

网络基础
   ↓
TCP/IP
   ↓
HTTP/HTTPS
   ↓
Linux
   ↓
Python
   ↓
JavaScript
   ↓
SQL
   ↓
Web开发基础
   ↓
常见漏洞
   ↓
API安全
   ↓
源码审计
   ↓
安全自动化

其中最重要的几个基础:

HTTP
Linux
Python
JavaScript
SQL

最好真正理解,而不是只背命令。


二十八、建议使用靶场学习

学习漏洞时,建议优先选择:

DVWA
OWASP Juice Shop
WebGoat
bWAPP

例如使用Docker运行Juice Shop:

docker pull bkimminich/juice-shop

然后:

docker run -d \
  --name juice-shop \
  -p 3000:3000 \
  bkimminich/juice-shop

查看:

docker ps

访问:

http://127.0.0.1:3000

这样可以在自己的隔离环境中学习:

漏洞原理
HTTP请求
代码缺陷
修复方法

二十九、从“漏洞”到“风险”

发现一个漏洞之后,不应该马上结束。

还需要继续分析:

谁可以触发?
需要什么权限?
影响什么数据?
会不会影响业务?
是否可以继续扩大影响?

例如:

漏洞:
越权

影响:
其他用户数据可以被读取

风险:
隐私泄露
业务风险
合规风险

一个成熟的安全报告不仅应该写:

存在漏洞

还应该写清楚:

漏洞原因
漏洞位置
影响范围
修复建议

三十、总结

Web安全看起来有很多漏洞:

SQL注入
XSS
CSRF
SSRF
文件上传
路径遍历
命令执行
越权

但很多漏洞最终都可以归纳成几个核心问题:

不可信输入
      ↓
不安全处理
      ↓
危险操作
      ↓
安全边界失效

因此学习Web安全时,与其记住几十种Payload,不如真正理解:

输入从哪里来?
数据去了哪里?
系统如何处理?
谁有权限?
哪里存在安全边界?

三十一、写给正在学习网络安全的人

刚开始学习Web安全时,很容易出现:

今天学SQL注入
明天学XSS
后天学Kali
再学Burp

最后发现:

每个都会一点,但是不会把知识串起来。

更合理的路线应该是:

网络
 ↓
系统
 ↓
编程
 ↓
Web
 ↓
漏洞
 ↓
靶场
 ↓
源码
 ↓
自动化

当你真正理解HTTP、Linux、Python、SQL和JavaScript以后,再去学习漏洞,会轻松很多。

因为很多“高级漏洞”最终还是建立在基础知识之上。


三十二、结语

Web安全真正值得学习的,并不是某一个固定Payload,而是一套稳定的分析方法:

找到输入点
   ↓
追踪数据流
   ↓
定位危险操作
   ↓
检查认证
   ↓
检查授权
   ↓
分析安全边界
   ↓
判断实际影响
   ↓
提出修复方案

SQL注入考验:

输入 + 数据库

XSS考验:

输入 + 输出 + 浏览器

越权考验:

身份 + 资源 + 权限

SSRF考验:

用户输入 + 服务器网络能力

命令执行考验:

用户输入 + 操作系统

所以,真正的Web安全能力,不是“会多少工具”,而是:

看到一个请求之后,能够快速判断数据去了哪里、谁可以访问、哪里存在安全边界。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

这才是网络安全学习中最值得长期积累的能力

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐