Compare commits

..

9 Commits

Author SHA1 Message Date
danny 18e40a85bc 第四章增加数据库表名的说明 2025-11-12 20:39:22 +08:00
danny 1f887cfd95 更新XSS漏洞防范策略 2025-11-11 14:52:50 +08:00
danny 5a7d8174f6 小修正 2025-11-05 10:12:05 +08:00
danny 784247b2ee 增加正则表达式 2025-11-05 09:05:42 +08:00
danny a59d7ee612 完成11章节 2025-11-03 09:51:45 +08:00
danny c9f82d5ea9 格式小修改 2025-11-03 09:01:00 +08:00
danny ae7f5b8273 格式小修改 2025-11-03 08:57:13 +08:00
danny 526799f142 更新目录 2025-11-01 09:41:39 +08:00
danny b2663bcaec 完成HTTP的简单描述 2025-11-01 09:35:47 +08:00
11 changed files with 671 additions and 14 deletions
+18 -3
View File
@@ -1,3 +1,18 @@
[第一章](第一章/01.md)
[第三章](第三章/01.md)
[第四章](第四章/01.md) # 目录
- [第一章](第一章/01.md)
- [第三章](第三章/01.md)
- [第四章](第四章/01.md)
- [第五章](第五章/01.md)
- [第六章](第六章/01.md)
- [第七章](第七章/01.md)
- [第八章](第八章/01.md)
- [第九章](第九章/01.md)
- [第十章](第十章/01.md)
- [第十一章](第十一章/01.md)
- 附录
- [HTTP简介](工具/http.md)
- [ASCII码表](工具/ascii.md)
- [正则表达式](工具/正则表达式.md)
Executable
+207
View File
@@ -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的默认端口是80HTTPS的默认端口是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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
</body>
</html>
```
### 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
<?php
session_start();
echo "hello";
?>
```
访问这个页面,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)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

+267
View File
@@ -0,0 +1,267 @@
- [1. 正则表达式函数](#1-正则表达式函数)
- [1.1. **匹配类函数**](#11-匹配类函数)
- [1.2. **替换类函数**](#12-替换类函数)
- [1.3. **分割与筛选**](#13-分割与筛选)
- [2. 正则表达式规则](#2-正则表达式规则)
- [2.1. **基础字符匹配**](#21-基础字符匹配)
- [2.2. **量词(控制匹配次数)**](#22-量词控制匹配次数)
- [2.3. **边界控制**](#23-边界控制)
- [2.4. **分组与引用**](#24-分组与引用)
- [2.5. **替代与条件匹配**](#25-替代与条件匹配)
- [2.6. **模式修饰符**](#26-模式修饰符)
- [2.7. **特殊结构**](#27-特殊结构)
- [2.8. **Unicode 支持**](#28-unicode-支持)
- [2.9. **示例**](#29-示例)
- [2.10. **注意事项**](#210-注意事项)
PHP提供了丰富的正则表达式函数,主要用于模式匹配、替换、分割等操作。以下是核心函数及其功能详解:
# 1. 正则表达式函数
## 1.1. **匹配类函数**
- **`preg_match()`**
执行单次正则匹配,返回匹配次数(0或1)。支持捕获组存储到`$matches`数组。
示例:匹配字符串中的数字
```php
php$text = "Order 12345";
preg_match('/Order \d+/', $text, $matches); // $matches[0] = "Order 12345"
```
- **`preg_match_all()`**
全局匹配,返回所有匹配结果到`$matches`数组。可通过`flags`参数(如`PREG_PATTERN_ORDER`)调整结果排序。
示例:提取HTML中的链接
```php
$html = '<a href="link1.html">Link1</a><a href="link2.html">Link2</a>';
preg_match_all('/<a href="(.*?)">(.*?)<\/a>/', $html, $matches);
// $matches[1] = ["link1.html", "link2.html"], $matches[2] = ["Link1", "Link2"]
```
## 1.2. **替换类函数**
- **`preg_replace()`**
执行正则替换,支持逆向引用(如`$1`)和数组替换。
示例:脱敏手机号
```php
$text = "用户电话:123-4567-8901";
$masked = preg_replace('/(\d{3})-(\d{4})-\d{4}/', '$1-****-$2', $text);
// 输出 "用户电话:123-****-4567"
```
- **`preg_replace_callback()`**
通过回调函数动态生成替换内容,灵活性更高。
示例:年份递增
```php
$text = "April fools day is 04/01/2002";
echo preg_replace_callback(
"|(\d{2}/\d{2}/)(\d{4})|",
function($m) { return $m[1] . ($m[2] + 1); },
$text
); // 输出 "04/01/2003"
```
- **`preg_filter()`**
类似`preg_replace`,但仅保留有替换结果的条目(忽略未匹配项)。
## 1.3. **分割与筛选**
- **`preg_split()`**
按正则规则分割字符串,返回数组。支持`limit`限制分割次数,`flags`调整结果格式(如`PREG_SPLIT_NO_EMPTY`过滤空项)。
示例:分割CSV
```php
$csv = "apple, orange; banana|pear";
$fruits = preg_split('/[,;|]/', $csv); // ["apple", "orange", "banana", "pear"]
```
- **`preg_grep()`**
筛选数组中匹配模式的元素。
示例:筛选有效邮箱
```php
$emails = ["test@qq.com", "invalid-email", "user@example.com"];
$valid = preg_grep('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $emails);
// 输出 ["test@qq.com", "user@example.com"]
```
# 2. 正则表达式规则
PHP 的正则表达式基于 **PCREPerl Compatible Regular Expressions** 库,其匹配规则与 Perl 正则高度兼容。以下是 PHP 正则表达式的核心匹配规则,涵盖字符匹配、量词、边界控制、分组等关键功能:
------
## 2.1. **基础字符匹配**
- **普通字符**:直接匹配对应字符(如 `a` 匹配字母 `a`)。
- **元字符**:需转义后匹配(如 `\.` 匹配点号 `.``\*` 匹配星号 `*`)。
```php
preg_match('/\.com/', 'example.com'); // 匹配 ".com"
```
- **特殊字符类**
- `\d`:匹配数字(等价于 `[0-9]`)。
- `\w`:匹配单词字符(字母、数字、下划线,等价于 `[a-zA-Z0-9_]`)。
- `\s`:匹配空白字符(空格、制表符、换行等)。
- 反义类:`\D`(非数字)、`\W`(非单词字符)、`\S`(非空白)。
------
## 2.2. **量词(控制匹配次数)**
| 量词 | 含义 | 示例 |
| ------- | ---------------------------- | --------------------------------- |
| `.` | 匹配单个任意字符(除换行符) | `a.b` 匹配 `aXb`、`a b` 等 |
| `*` | 匹配 0 次或多次 | `a*` 匹配 `""`, `a`, `aa` |
| `+` | 匹配 1 次或多次 | `a+` 匹配 `a`, `aa` |
| `?` | 匹配 0 次或 1 次 | `a?` 匹配 `""` 或 `a` |
| `{n}` | 精确匹配 n 次 | `a{3}` 匹配 `aaa` |
| `{n,}` | 匹配至少 n 次 | `a{2,}` 匹配 `aa`, `aaa` |
| `{n,m}` | 匹配 n 到 m 次 | `a{2,4}` 匹配 `aa`, `aaa`, `aaaa` |
**贪婪 vs 非贪婪**
- 默认贪婪模式(匹配尽可能多的字符),如 `.*` 会匹配整个字符串。
- 非贪婪模式(在量词后加 `?`),如 `.*?` 匹配最短可能。
```php
$text = "<div>content</div>";
preg_match('/<div>(.*?)<\/div>/', $text, $matches); // $matches[1] = "content"
```
------
## 2.3. **边界控制**
- **锚点**
- `^`:匹配字符串开头(多行模式下匹配行首)。
- `$`:匹配字符串结尾(多行模式下匹配行尾)。
```php
preg_match('/^Hello/', 'Hello world'); // 匹配成功
preg_match('/world$/', 'Hello world'); // 匹配成功
```
- **单词边界**
- `\b`:匹配单词边界(如 `\bword\b` 匹配独立单词 `word`)。
- `\B`:匹配非单词边界;可以认为是 `\b`的反义。
```php
preg_match('/\bcat\b/', 'The cat sat'); // 匹配 "cat"
preg_match('/\bcat\b/', 'category'); // 不匹配
```
------
## 2.4. **分组与引用**
- **捕获组**:用 `( )` 包裹,匹配内容会被捕获到 `$matches` 数组。
```php
preg_match('/(\d{4})-(\d{2})/', '2023-05', $matches);
// $matches[0] = "2023-05", $matches[1] = "2023", $matches[2] = "05"
```
- **非捕获组**:用 `(?: )` 包裹,不捕获内容(提升性能)。
```php
preg_match('/(?:\d{3})-(\d{4})/', '123-4567', $matches);
// $matches[1] = "4567"(仅捕获第二组)
```
- **反向引用**:用 `\n`n 为组号)引用已捕获的内容。
```php
preg_match('/(\w+)\s\1/', 'test test', $matches); // 匹配重复单词
```
------
## 2.5. **替代与条件匹配**
- **分支匹配**:用 `|` 表示“或”关系。
```php
preg_match('/(cat|dog)/', 'I have a cat'); // 匹配 "cat"
```
- **条件匹配**PCRE 支持 `(?(condition)yes|no)` 语法(较少用)。
------
## 2.6. **模式修饰符**
修饰符放在定界符后(如 `/pattern/i`),常用如下:
| 修饰符 | 含义 | 示例 |
| ------ | ---------------------------------- | ---------------------------- |
| `i` | 不区分大小写 | `/hello/i` 匹配 `Hello` |
| `m` | 多行模式(`^` 和 `$` 匹配行首/尾) | `/^line/m` 匹配每行开头 |
| `s` | 让 `.` 匹配换行符 | `/.*./s` 匹配跨行文本 |
| `u` | 支持 UTF-8 编码 | `/\p{L}/u` 匹配 Unicode 字母 |
| `x` | 忽略模式中的空白和注释 | `/a b /x` 匹配 `ab` |
| `e` | 匹配后的字符串作为php执行 | 新版本已经取消 |
------
## 2.7. **特殊结构**
- **环视(Lookaround**
- 正向环视:`(?=pattern)`(后面必须跟 `pattern`),`(?!pattern)`(后面不能跟 `pattern`)。
- 反向环视:`(?<=pattern)`(前面必须是 `pattern`),`(?<!pattern)`(前面不能是 `pattern`)。
```php
preg_match('/(?<=\d)abc/', '123abc'); // 匹配 "abc"(前面是数字)
```
- **原子组**`(?>pattern)` 防止回溯(性能优化)。
------
## 2.8. **Unicode 支持**
- 使用 `\p{L}` 匹配任意字母,`\p{N}` 匹配数字,需配合 `u` 修饰符。后一个`/`后面可以有模式修饰符`i``m``s``u``x`等。
```php
preg_match('/\p{L}+/u', '中文'); // 匹配 "中文"
```
------
## 2.9. **示例**
模式匹配字符串的开始和结束一般是`/`(PHP可以有其他的替代,具体请参考手册);
```php
// 匹配邮箱
$email = "user@example.com";
if (preg_match('/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $email)) {
echo "Valid email";
}
// 提取日期(YYYY-MM-DD
$text = "Today is 2023-05-20";
preg_match('/\b(\d{4})-(\d{2})-(\d{2})\b/', $text, $matches);
// $matches[1] = "2023", $matches[2] = "05", $matches[3] = "20"
```
------
## 2.10. **注意事项**
1. **转义字符**:在双引号字符串中,`\` 可能被转义,建议用单引号或额外转义。
2. **性能**:避免过度使用嵌套分组或回溯复杂的模式。
3. **错误处理**:检查 `preg_last_error()` 调试复杂正则。
PHP 正则表达式功能强大,合理使用可高效处理字符串匹配、验证和提取任务。
+7 -5
View File
@@ -190,6 +190,8 @@ http://localhost/2020CodeAudit/c8/8-3-phpinput.php
![image-20251030153450203](img/image-20251030153450203.png) ![image-20251030153450203](img/image-20251030153450203.png)
前面的例子中可以通过该方式注入PHP代码。
## 3.2. php://output和php://filter ## 3.2. php://output和php://filter
- php://output:将流数据输出 - php://output:将流数据输出
@@ -324,7 +326,7 @@ http://localhost/2020CodeAudit/c8/8-6-pregrematch-1.php
## 6.2. 特殊字符未转义 ## 6.2. 特殊字符未转义
在正则表达式里,所有能被正则表达式引擎解析的字符都算是特殊字符,而在匹配这些字符的原字符时需要使用反斜杠(\)来进行转义,如果不进行转义,像样英文句号(.)则可用来表示任何字符,存在安全隐患 在正则表达式里,所有能被正则表达式引擎解析的字符都算是特殊字符,而在匹配这些字符的原字符时需要使用反斜杠(\\\)来进行转义,如果不进行转义,像样英文句号(.)则可用来表示任何字符,存在安全隐患
```php ```php
<?php <?php
@@ -502,10 +504,10 @@ http://localhost/2020CodeAudit/c8/8-8-findfirstfile.php?file=1<<
echo "PHP可变变量-phpinfo的用法举例:"."<br />"; echo "PHP可变变量-phpinfo的用法举例:"."<br />";
//以下八条语句,都可以执行phpinfo //以下八条语句,都可以执行phpinfo
//$a = "${@phpinfo()}"; //$a = "${@phpinfo()}";
//$a = "${ phpinfo()}"; //$a = "${ phpinfo()}"; // 空格
$a = "${ phpinfo()}"; $a = "${ phpinfo()}"; // TAB
//$a = "${/**/phpinfo()}"; //$a = "${/**/phpinfo()}";
// $a = "${ // $a = "${ // 分行,回车
// phpinfo()}"; // phpinfo()}";
//$a = "${+phpinfo()}"; //$a = "${+phpinfo()}";
// $a = "${-phpinfo()}"; // $a = "${-phpinfo()}";
+2 -2
View File
@@ -160,7 +160,7 @@ echo $a;
? ?
``` ```
解析:如果只通过GET提交a=1,无POST/COOKIE则$_REQUEST=_GET$$_REQUEST==$_GET。 解析:如果只通过GET提交a=1,无POST/COOKIE则```$_REQUEST=_GET``````$$_REQUEST==$_GET```
``` ```
http://localhost/2020CodeAudit/C6/6-1-1-2-cover-1.php?a=2 http://localhost/2020CodeAudit/C6/6-1-1-2-cover-1.php?a=2
@@ -278,7 +278,7 @@ Array
## 1.3. 变量覆盖漏洞防范 ## 1.3. 变量覆盖漏洞防范
- 不进行变量注册,建议直接用原生的$_GET、$_POST等数组变量进行操作。 - 不进行变量注册,建议直接用原生的```$_GET```、```$_POST```等数组变量进行操作。
- 如果考虑程序可读性等原因,需要注册个别变量,可以直接在代码中定义变量,然后再把请求中的值赋值给它。如果一定要使用前面几种方式注册变量,可以在注册变量前先判断变量是否存在 - 如果考虑程序可读性等原因,需要注册个别变量,可以直接在代码中定义变量,然后再把请求中的值赋值给它。如果一定要使用前面几种方式注册变量,可以在注册变量前先判断变量是否存在
- 如使用extract()函数则可以配置第二个参数为EXTR_ SKIP。使用parse_str()函数注册变量前需要先自行通过代码判断变量是否存在。 - 如使用extract()函数则可以配置第二个参数为EXTR_ SKIP。使用parse_str()函数注册变量前需要先自行通过代码判断变量是否存在。
- 不建议使用import_request_variables()函数注册全局变量 - 不建议使用import_request_variables()函数注册全局变量
+156 -4
View File
@@ -1,9 +1,161 @@
- 要打造安全的应用程序,要从业务功能的设计开始 - [1. 验证码](#1-验证码)
- 验证码、用户登录、用户注册、密码找回、资料操作、投票、积分、抽奖、充值支付、私信反馈、文件管理、 数据库管理以及命令执行等功能容易出现安全问题 - [1.1. 用户登录](#11-用户登录)
- [1.1.1. 撞库漏洞](#111-撞库漏洞)
- [1.1.2. API 登录](#112-api-登录)
- [1.1.3. 用户注册](#113-用户注册)
- [1.1.4. 密码找回的安全设计思路](#114-密码找回的安全设计思路)
- [1.2. 资料查看与修改的安全设计思路](#12-资料查看与修改的安全设计思路)
- [1.3. 投票/积分/抽奖的安全设计思路](#13-投票积分抽奖的安全设计思路)
- [1.4. 充值支付的安全设计思路](#14-充值支付的安全设计思路)
- [1.5. 私信及反馈的安全设计思路](#15-私信及反馈的安全设计思路)
- [1.6. 远程地址访问的安全设计思路](#16-远程地址访问的安全设计思路)
- [1.7. 文件管理的安全设计思路](#17-文件管理的安全设计思路)
- [1.8. 数据库管理的安全设计思路](#18-数据库管理的安全设计思路)
- [1.9. 命令/代码执行的安全设计思路](#19-命令代码执行的安全设计思路)
- [1.10. 文件/数据库备份的安全设计思路](#110-文件数据库备份的安全设计思路)
- [1.11. API的安全设计思路](#111-api的安全设计思路)
# 验证码 # 1. 验证码
- 验证码有图片验证码、滑动验证码、短信/邮箱/电话、二维码等分类 - 验证码有图片验证码、滑动验证码、短信/邮箱/电话、二维码等分类
- 而据保守估计起码有80%以上的验证码是存在可以爆破和简单识别的问题,设计一个有效的验证码尤为重要 - 而据保守估计起码有80%以上的验证码是存在可以爆破和简单识别的问题,设计一个有效的验证码尤为重要
## 验证码不刷新导致直接绕过 **验证码不刷新导致直接绕过**
- 验证码能够多次使用的原因是后端程序在接收一次请求后,并没有主动刷新验证码
- 部分比较大的业务使用了负载均衡,验证码跟Session绑定在一起,为了能够保证验证码能够正常使用,所以会把验证码明文或者加密后放在Cookie或者POST数据包里面
- 所以每次只要同一个数据包里面的两个验证码对上了即可绕过
**验证码暴力破解**
- 注册或者找回密码等敏感操作时的手机或者邮箱验证码能够爆破
- 主要是因为程序没有设置验证码错误次数和超时,导致能够不断进行尝试
**验证码机器识别**
图片验证码的机器识别,有两种情况:
- 一种是针对不是实时生成的验证码,已经生成了部分的验证码在服务器端保存,前端直接加载验证。这类是最好绕过的,只要把全部的验证码文件保存回来,做一个图片MD5库,然后利用的时候直接匹配服务器端返回的图片MD5即可识别。
- 另外一种是动态生成的验证码,这类需要做一些图片文字识别或者语音识别
**验证码打码平台**
> 打码是网络兼职数据录入工作的一种,指通过人工识别并输入验证码以协助自动化程序绕过[图灵测试](https://baike.baidu.com/item/图灵测试/1701255?fromModule=lemma_inlink)的行为,常见于批量注册账号、群发广告等场景。
**强壮的验证码**
1. 设置验证码错误次数
2. 不把验证码放到HTML页面或者Cookie中。
3. 验证码要设置只能请求一次,请求一次后不管错误与否都在后端程序强制刷新。
4. 短信或者邮件验证码必须要6位以上字母和数字混合,图片或者语音验证码要加强混淆干扰,比如图片文字变形,增加干扰斑点等。语音验证码增加背景噪声。
5. 验证码要动态生成,不能统一生成多次调用
## 1.1. 用户登录
### 1.1.1. 撞库漏洞
撞库漏洞是指登录口没有做登录次数限制,导致可以使用不同的用户及密码进行不断的登录尝试,以遍历用户密码;也可以理解为登录爆破。
- 用户名和密码错误次数都无限制
- 单时间段内用户的密码错误次数限制
- 单时间段内IP登录错误次数限制
- 针对撞库漏洞比较好的解决方案是使用登录验证码和多因素认证
### 1.1.2. API 登录
- 登录密钥(clientkey)需要不可预测并且不固定,生成key的算法中加入随机字符。
- API接口禁止搜索引擎收录。
- 登录密钥当次绑定当前主机,换机器不可用,防止QQ木马和嗅探key。
案例:193页
### 1.1.3. 用户注册
垃圾注册,机器注册是比较头痛的问题。如何抵御恶意注册?
1. 设计验证码采
2. 集用户机器唯一识别码,
3. 拦截短时间内多次注册
4. 根据账号格式自学习识别垃圾账号
5. 防止SQL注入漏洞与XSS漏洞
### 1.1.4. 密码找回的安全设计思路
195页
1. 输入用户名、手机、邮箱阶段:存在完全或者部分显示隐私信息;或者服务器没有严格验证,依靠客户端提交的数据。
2. 添加验证码和新密码阶段:验证凭证简单,可能暴力破解;没有限定次数;Token验证可以预测(机器伪造爆破);凭证在源代码中。
3. 发送密码阶段:凭证和用户间关系没有严格验证
基本思路
- 接收验证码的邮箱和手机号不可由用户控制,直接从数据库中读取。
- 加强验证凭证复杂度,防止被暴力破解。
- 限制验证凭证错误次数验证凭证设置失效时间。
- 验证凭证不要保存在页面。输入用户邮箱或ID、手机号取验证凭证的地方需要设置验证码防止短信炸弹和批量找回等。
- 验证凭证跟用户名、用户ID、用户邮箱绑定,找回密码时验证当前凭证是否是当前用户的。
## 1.2. 资料查看与修改的安全设计思路
197页的案例。背景知识:[HTTP、Cookie、Session](../工具/http.md)
- 用户资源ID (订单ID、地址ID等等)绑定到用户,只允许有权限的用户查看。
- 当前用户信息存储到session,不放到request中,避免攻击者修改当前用户ID
## 1.3. 投票/积分/抽奖的安全设计思路
199页案例。
- 机器识别码验证,每台机器都可以根据硬件信息生成唯一的识别码。
- 操作需要登录,当前用户信息从session中读取。
## 1.4. 充值支付的安全设计思路
- 保证数据可信,商品单价及总价不可从客户端获取
- 购买数量不能小于等于0,<65536。
- 账户支付锁定机制,当一个支付操作开始就应该立马锁定当前账户,不能同时两个后端请求对余额进行操作
## 1.5. 私信及反馈的安全设计思路
201页案例,利用XSS漏洞获取管理员cookie。
- 将特殊字符进行过滤
- 使用白名单和黑名单结合的方式。
## 1.6. 远程地址访问的安全设计思路
- 限制填写内网地址
- 考虑短地址的问题
## 1.7. 文件管理的安全设计思路
- 禁止写入脚本可在服务器端执行的文件
- 限制文件管理功能操作的目录
- 限制文件管理功能访问权限
- 禁止上传特殊字符文件名的文件
## 1.8. 数据库管理的安全设计思路
- 限制可以操作的数据库表,如果是数据库备份可以直接在代码里面写死只能操作哪些表,如果是执行SQL语句的方式可以另建一个MySQL用户,限制可以操作的表和字段。
- 限制备份到服务器上的文件名,需要系统随机生成类似md5并且长度不能低于16位,扩展名不能自定义
## 1.9. 命令/代码执行的安全设计思路
- 严格控制该功能访问权限,建议高权限才能访问。
- 在满足业务需求的情况下,可以设置命令白名单,可使用escapeshellcmd()以 及escapeshellarg()函数进行过滤,命令直接写死在代码中更好。
- 给命令及代码执行功能设置独立密码。
- 代码执行功能限制脚本可访问的路径。
- 在满足需求的情况下限制当前执行命令的系统用户权限。
## 1.10. 文件/数据库备份的安全设计思路
207页解释。
- 进行权限控制,由于备份功能是一个非常高危敏感的功能,一定要限制高权限才能使用。
- 文件名随机生成,不可预测,可以把当前时间戳加上6位以上字母和数字随机生成的字符串进行md5来做为文件名。
## 1.11. API的安全设计思路
- 访问权限控制
- 防止敏感信息泄露
- SQL注入等常规漏洞
+14
View File
@@ -6,6 +6,7 @@
- [1.2.3. espcms搜索注入分析](#123-espcms搜索注入分析) - [1.2.3. espcms搜索注入分析](#123-espcms搜索注入分析)
- [1.3. 漏洞防范](#13-漏洞防范) - [1.3. 漏洞防范](#13-漏洞防范)
- [2. XSS漏洞](#2-xss漏洞) - [2. XSS漏洞](#2-xss漏洞)
- [2.1. XSS漏洞防范](#21-xss漏洞防范)
- [3. CSRF漏洞(跨站请求伪造)](#3-csrf漏洞跨站请求伪造) - [3. CSRF漏洞(跨站请求伪造)](#3-csrf漏洞跨站请求伪造)
- [3.1. Discuz CSRF备份拖库分析](#31-discuz-csrf备份拖库分析) - [3.1. Discuz CSRF备份拖库分析](#31-discuz-csrf备份拖库分析)
- [3.2. CSRF漏洞防范](#32-csrf漏洞防范) - [3.2. CSRF漏洞防范](#32-csrf漏洞防范)
@@ -337,6 +338,17 @@ http://localhost/74cms/admin/admin_index.php
<span style="color:#FF6600" title="&lt;img src=1 onerror=alert(1) border=0/&gt;" class="vtip">[logo]</span> <span style="color:#FF6600" title="&lt;img src=1 onerror=alert(1) border=0/&gt;" class="vtip">[logo]</span>
``` ```
## 2.1. XSS漏洞防范
- 过滤掉相关的特殊字符
- 标签事件属性黑白名单
- 输出编码:htmlspecialchars()函数
- 防御DOM XSS
- 避免客户端敏感操作
- 分析和强化客户端的JavaScript代码
- Anti-XSS
- HttpOnly
# 3. CSRF漏洞(跨站请求伪造) # 3. CSRF漏洞(跨站请求伪造)
CSRF主要是用于越权操作所有漏洞自然在有权限控制的地方,像管理后台、会员中心、论坛帖子以及交易管理等从白盒角度来说,只要读代码的时候看看几个核心文件里面有没有验证token和referer相关的代码这里的核心文件指的是被大量文件引用的基础文件。 CSRF主要是用于越权操作所有漏洞自然在有权限控制的地方,像管理后台、会员中心、论坛帖子以及交易管理等从白盒角度来说,只要读代码的时候看看几个核心文件里面有没有验证token和referer相关的代码这里的核心文件指的是被大量文件引用的基础文件。
@@ -374,6 +386,8 @@ $backupfilename = './data/'.$backupdir.'/'.str_replace(array('/', '\\', '.', "'"
http://localhost/discuz/admin.php?action=db&operation=export&setup=1&scrolltop=&anchor=&type=custom&customtables[]=pre_ucenter_admins&method=multivol&sizelimit=2048&extendins=0&sqlcompat=&usehex=1&usezip=0&filename=xinan&exportsubmit=%CC%E1%BD%BB22 http://localhost/discuz/admin.php?action=db&operation=export&setup=1&scrolltop=&anchor=&type=custom&customtables[]=pre_ucenter_admins&method=multivol&sizelimit=2048&extendins=0&sqlcompat=&usehex=1&usezip=0&filename=xinan&exportsubmit=%CC%E1%BD%BB22
``` ```
> 注意,URL地址中有个参数是你需要备份的数据表的名字,请确认和你的安装数据表名是一致的。
思考:如何得到漏洞的访问地址? 思考:如何得到漏洞的访问地址?
## 3.2. CSRF漏洞防范 ## 3.2. CSRF漏洞防范