diff --git a/工具/http.md b/工具/http.md new file mode 100755 index 0000000..2b9fe67 --- /dev/null +++ b/工具/http.md @@ -0,0 +1,207 @@ +- [1. HTTP协议](#1-http协议) + - [1.1. HTTP请求](#11-http请求) + - [1.1.1. Head](#111-head) + - [1.1.1.1. **方法(Method)**](#1111-方法method) + - [1.1.1.2. Host](#1112-host) + - [1.1.1.3. 其他头](#1113-其他头) + - [1.1.2. Body](#112-body) + - [1.2. HTTP回应](#12-http回应) + - [1.2.1. head](#121-head) + - [1.2.2. body](#122-body) +- [2. 什么是cookie](#2-什么是cookie) + - [2.1. **核心作用**](#21-核心作用) + - [2.2. **工作原理**](#22-工作原理) +- [3. session](#3-session) + + +# 1. HTTP协议 + +HTTP(HTTPS)是建立在TCP协议层上的应用层协议。区别在于HTTP使用明文传输,HTTPS是在SSL加密层上进行传输的。SSL加密层可以看成是TCP的扩展,因此在应用层上,HTTP和HTTP可以看成是一样的。 + +HTTP的默认端口是80;HTTPS的默认端口是443。 + +另外为了提升服务器的负载能力,HTTP是应答完成后就断开TCP的方式。 + +![alt text](img/http_connect.drawio.png) + +HTTP是纯文本的应用层协议,无论是Request或者是Response都是一致的结构,分为头(head)和体(body)两个部分。 + +一个典型的Request由客户端发起: + +```http +GET /index.php?a=1&b=2 HTTP/1.1 +Host: localhost +sec-ch-ua: "Not.A/Brand";v="99", "Chromium";v="136" +sec-ch-ua-mobile: ?0 +sec-ch-ua-platform: "Linux" +Accept-Language: zh-CN,zh;q=0.9 +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7 +Sec-Fetch-Site: none +Sec-Fetch-Mode: navigate +Sec-Fetch-User: ?1 +Sec-Fetch-Dest: document +Accept-Encoding: gzip, deflate, br +Cookie: Lg4E_2132_saltkey=FQXT9TSx; Lg4E_2132_lastvisit=1761101776; Lg4E_2132_ulastactivity=e3c3eG8C3HO%2FWXweKkNzw5nEuS2QRbsVqRZ82RGJGMn3uL7a3K1D; Lg4E_2132_nofavfid=1; Lg4E_2132_visitedfid=2; Lg4E_2132_smile=1D1; Lg4E_2132_lastcheckfeed=1%7C1761124759; DedeUserID=2; DedeUserID__ckMd5=1be68b23ddcae297; PHPSESSID=0eae6bcf13b88d56b155bb3e33921404; DedeLoginTime=1761882038; DedeLoginTime__ckMd5=4e7ad3dc7f3a81b5 +Connection: keep-alive +Content-Type: application/x-www-form-urlencoded + +b=2 +``` + +整个的HTTP协议由head和body构成;head和body之间用一个空行隔开。 + +## 1.1. HTTP请求 + +### 1.1.1. Head + +#### 1.1.1.1. **方法(Method)** + +```http +GET /index.php?a=1&b=2 HTTP/1.1 +``` +方法行定义了三个部分, + +第一个部分是方法,常见的方法如下: + +- `GET`:获取资源(如网页、文件)。 +- `POST`:提交数据(如表单、文件上传)。 +- `PUT`:更新资源。 +- `DELETE`:删除资源。 +- `HEAD`:仅获取响应头。 +- `OPTIONS`:查询服务器支持的通信选项。 + +第二个部分是请求资源的路径以及GET参数: + +```http +/index.php?a=1&b=2 +``` + +这里的路径是 ```/index.php``` 问好后面的是参数列表,多个参数用```&```进行分割;注意这里路径应该符合URL的编码规则。 + +第三部分是HTTP的版本号。 + +#### 1.1.1.2. Host + +```http +Host: localhost +``` + +host表示的是请求的主机(host)的域名、IP地址均可。主机名或者是ip地址后面可以带端口号(tcp监听端口),如果不带,表示默认端口80。 + +```http +Host: localhost +``` + +```http +Host: www.test.com:8080 +``` + +#### 1.1.1.3. 其他头 + +其他头由很多,比如 cookie,用到的时候再讲解。 + +### 1.1.2. Body + +body部分是请求的附加数据,例如Post的数据;发送的文件等。 + +## 1.2. HTTP回应 + +```http +HTTP/1.1 200 OK +Server: nginx/1.15.11 +Date: Fri, 31 Oct 2025 03:53:44 GMT +Content-Type: text/html +Connection: keep-alive +X-Powered-By: PHP/5.2.17 +Content-Length: 63690 + + + + + + + + +``` + +### 1.2.1. head + +响应头中最重要的是 + +```http +HTTP/1.1 200 OK +``` + +后面的 200 表示响应代码,OK 表示响应代码的描述。具体的响应代码可以查看[HTTP响应码](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Reference/Status)。 + +### 1.2.2. body + +根据请求的资源,返回的响应具体内容。可以是几乎任何的文档,包括html、文件、图片等。 + +# 2. 什么是cookie + +**Cookie 是网站存储在用户设备(如电脑、手机)上的小型数据文件**,主要用于记录用户信息、跟踪行为或保持会话状态。以下是简单解释: + +## 2.1. **核心作用** + +1. **记住用户信息** + - 例如:登录网站后,下次访问时自动填充用户名/密码(需用户允许)。 + - 保存偏好设置(如语言、主题颜色)。 +2. **跟踪用户行为** + - 广告商通过 Cookie 记录你的浏览习惯,推送相关广告(如你搜过鞋子后,其他网站显示鞋类广告)。 +3. **维持会话状态** + - 购物车功能依赖 Cookie:即使你关闭页面再打开,商品仍保留在购物车中。 + +## 2.2. **工作原理** + +1. **服务器发送 Cookie** + - 当你访问网站时,服务器可能通过 HTTP 响应头(如 `Set-Cookie`)发送一个或多个 Cookie 到你的浏览器。 +2. **浏览器存储 Cookie** + - 浏览器将 Cookie 保存在本地文件或内存中(按域名分类,不同网站互不干扰)。 +3. **后续请求携带 Cookie** + - 再次访问同一网站时,浏览器会自动在 HTTP 请求头中附加相关 Cookie,服务器据此识别用户。 + +简单说来,cookie 就是存储在客户端的一段数据,在访问相同的域名的时候(可能还会限制域名下面的路径),会自动发送给服务器。cookie可以由response中的head字段发送给客户端(服务器向客户端写cookie);也可以在客户端通过js读取和设置cookie(客户端读写cookie)。这样服务器就可以记住客户端是谁。例如把用户ID存放在cookie中,每次都自动发送给服务器(在head中),服务器就会知道收到的request是谁发送的。 + +但是在客户端存放敏感信息是一种不安全的做法,客户端的环境是不可控的,cookie可能会被伪造。这样我们就需要使用到session来解决这个问题。 + +> 注意:cookie 的存放有两个重要参数,第一是作用域,其实就是路径;第二就是过期时间。 + +# 3. session + +显然cookie值可以在客户端进行读写,如果把敏感信息存放到cookie中是不安全的。因此服务器需要识别到底是哪个客户端的访问情况就需要使用到session。 + +Session是存放在服务器的数据,一般用来存放某个用户的信息。当客户端访问服务器,服务器就会读取出客户端对应的Session,从而知道是那个客户端发起的请求。 + +那么服务器是如何知道是哪个客户端访问服务器,并读取出该客户端对应的Session?这就需要使用到cookie。注意cookie的特点,服务器是可以设置cookie的,通过response中在回应头加入相应的cookie字段,客户端收到该回应就会设置自己的cookie;以后每次访问服务器就会自动发送该cookie。 + +```php + +``` + +访问这个页面,F12打开调试。 + +![image-20251101092415063](img/image-20251101092415063.png) + +在4这个位置可以看到服务通过返回头设置了客户端的的一个cookie,这个cookie 就对应服务器的session。进一步验证,在客户端的cookie中可以看到这个值(4位置)。 + +![image-20251101092635998](img/image-20251101092635998.png) + +在后续的访问中,这个cookie值被自动发送给服务器,服务器就通过这个值来和服务器端的session联系起来,确定是那个客户端在发出请求。 + +就好像是给每个客户端临时进行了编号,通过编号就能只能是谁在访问。同时session在服务器端是一个数组,数组中可以增加,修改项目,用来存放该用户的状态或者是临时数据。例如是否登陆、用户ID等。 + +Session的读取是自动的,通过$_SESSION 数组来进行读写。另外session也是有过期时间的。 + +这样,客户端只用在cookie中存放一个随机字符串,服务器就可以读取在服务器端对应的session来获得该用户的信息,要比把敏感信息放在cookie中安全很多。 + +> 注意:老的浏览器可能不支持cookie,因此也可以把上述的PHPSESSION这个字符串通过GET参数传递给服务器。 + +关于SESSION的配置,在phpinfo中有详细的描述: + +![image-20251101093410723](img/image-20251101093410723.png) diff --git a/工具/img/http_connect.drawio.png b/工具/img/http_connect.drawio.png new file mode 100755 index 0000000..5912d83 Binary files /dev/null and b/工具/img/http_connect.drawio.png differ diff --git a/工具/img/image-20251101092415063.png b/工具/img/image-20251101092415063.png new file mode 100755 index 0000000..e333c7a Binary files /dev/null and b/工具/img/image-20251101092415063.png differ diff --git a/工具/img/image-20251101092635998.png b/工具/img/image-20251101092635998.png new file mode 100755 index 0000000..dbc6650 Binary files /dev/null and b/工具/img/image-20251101092635998.png differ diff --git a/工具/img/image-20251101093410723.png b/工具/img/image-20251101093410723.png new file mode 100755 index 0000000..04ae014 Binary files /dev/null and b/工具/img/image-20251101093410723.png differ diff --git a/第十一章/01.md b/第十一章/01.md index 7479f0a..f14fd26 100755 --- a/第十一章/01.md +++ b/第十一章/01.md @@ -6,4 +6,79 @@ - 验证码有图片验证码、滑动验证码、短信/邮箱/电话、二维码等分类 - 而据保守估计起码有80%以上的验证码是存在可以爆破和简单识别的问题,设计一个有效的验证码尤为重要 -## 验证码不刷新导致直接绕过 \ No newline at end of file +**验证码不刷新导致直接绕过** + +- 验证码能够多次使用的原因是后端程序在接收一次请求后,并没有主动刷新验证码 +- 部分比较大的业务使用了负载均衡,验证码跟Session绑定在一起,为了能够保证验证码能够正常使用,所以会把验证码明文或者加密后放在Cookie或者POST数据包里面 +- 所以每次只要同一个数据包里面的两个验证码对上了即可绕过 + +**验证码暴力破解** + +- 注册或者找回密码等敏感操作时的手机或者邮箱验证码能够爆破 +- 主要是因为程序没有设置验证码错误次数和超时,导致能够不断进行尝试 + +**验证码机器识别** + +图片验证码的机器识别,有两种情况: + +- 一种是针对不是实时生成的验证码,已经生成了部分的验证码在服务器端保存,前端直接加载验证。这类是最好绕过的,只要把全部的验证码文件保存回来,做一个图片MD5库,然后利用的时候直接匹配服务器端返回的图片MD5即可识别。 +- 另外一种是动态生成的验证码,这类需要做一些图片文字识别或者语音识别 + +**验证码打码平台** + +> 打码是网络兼职数据录入工作的一种,指通过人工识别并输入验证码以协助自动化程序绕过[图灵测试](https://baike.baidu.com/item/图灵测试/1701255?fromModule=lemma_inlink)的行为,常见于批量注册账号、群发广告等场景。 + +**强壮的验证码** + +1. 设置验证码错误次数 +2. 不把验证码放到HTML页面或者Cookie中。 +3. 验证码要设置只能请求一次,请求一次后不管错误与否都在后端程序强制刷新。 +4. 短信或者邮件验证码必须要6位以上字母和数字混合,图片或者语音验证码要加强混淆干扰,比如图片文字变形,增加干扰斑点等。语音验证码增加背景噪声。 +5. 验证码要动态生成,不能统一生成多次调用 + +## 用户登录 + +### 撞库漏洞 + +撞库漏洞是指登录口没有做登录次数限制,导致可以使用不同的用户及密码进行不断的登录尝试,以遍历用户密码;也可以理解为登录爆破。 + +- 用户名和密码错误次数都无限制 +- 单时间段内用户的密码错误次数限制 +- 单时间段内IP登录错误次数限制 +- 针对撞库漏洞比较好的解决方案是使用登录验证码和多因素认证 + +### API 登录 + +- 登录密钥(clientkey)需要不可预测并且不固定,生成key的算法中加入随机字符。 +- API接口禁止搜索引擎收录。 +- 登录密钥当次绑定当前主机,换机器不可用,防止QQ木马和嗅探key。 + +案例:193页 + +### 用户注册 + +垃圾注册,机器注册是比较头痛的问题。如何抵御恶意注册? + +1. 设计验证码采 +2. 集用户机器唯一识别码, +3. 拦截短时间内多次注册 +4. 根据账号格式自学习识别垃圾账号 +5. 防止SQL注入漏洞与XSS漏洞 + +### 密码找回的安全设计思路 + +195页 + +1. 输入用户名、手机、邮箱阶段:存在完全或者部分显示隐私信息;或者服务器没有严格验证,依靠客户端提交的数据。 +2. 添加验证码和新密码阶段:验证凭证简单,可能暴力破解;没有限定次数;Token验证可以预测(机器伪造爆破);凭证在源代码中。 +3. 发送密码阶段:凭证和用户间关系没有严格验证 + +基本思路 + +- 接收验证码的邮箱和手机号不可由用户控制,直接从数据库中读取。 +- 加强验证凭证复杂度,防止被暴力破解。 +- 限制验证凭证错误次数验证凭证设置失效时间。 +- 验证凭证不要保存在页面。输入用户邮箱或ID、手机号取验证凭证的地方需要设置验证码防止短信炸弹和批量找回等。 +- 验证凭证跟用户名、用户ID、用户邮箱绑定,找回密码时验证当前凭证是否是当前用户的。 + +## 资料查看与修改的安全设计思路 \ No newline at end of file