Cookie&Session&Token
Cookie
- 服务器将用户名、用户ID或其他特征信息经过编码(加密或签名)后发送给用户,而服务器不储存这串字符,当用户访问需要验证身份的页面时,将这串字符串作为cookie传给服务器,服务器解码后查询数据库进行校验。
// 设置加密密钥
$key = "mySecretEncryptionKey";
// 加密并设置Cookie
function setEncryptedCookie($name, $value, $expire, $path, $key) {
$encryptedValue = openssl_encrypt($value, 'AES-128-ECB', $key);
setcookie($name, $encryptedValue, $expire, $path);
}
// 解密Cookie
function getDecryptedCookie($name, $key) {
if (isset($_COOKIE[$name])) {
return openssl_decrypt($_COOKIE[$name], 'AES-128-ECB', $key);
}
return null;
}
// 使用示例
setEncryptedCookie("username", "exampleUser", time() + 3600, "/", $key);
echo getDecryptedCookie("username", $key); // 输出解密后的值
Session
- 一般只在用户活跃时生效,用户断开连接时就失效。服务器为用户生成一串随机字符串作为session ID,并生成以该ID为名的文件(或者数据库条目),其中存储用户的省份信息、用户状态、行为偏好等。当用户访问需要验证身份的页面时,将session ID附加到cookie字段中传递给服务器,服务器查询文件校验身份和用户状态。这种方式相比于cookie更安全,首先其只在用户活跃时生效,其次敏感信息保存在服务器中,其他人不易获取。但缺点是较大的消耗服务器的内存资源。
// 启动Session
session_start();
// 设置Session变量
$_SESSION["username"] = "exampleUser";
// 读取Session变量
if(isset($_SESSION["username"])) {
echo "Welcome, " . htmlspecialchars($_SESSION["username"]);
} else {
echo "Please log in.";
}
Token
- 服务器将用户的身份信息(如用户名、用户ID等)通过哈希或MD5对这些信息进行签名,然后再将签名与省份信息拼接后再进行对称加密,将加密完成后的字符串发送给用户,当用户访问需要验证身份的页面时,将字符串附加到cookie字段中发送给服务器,服务器通过先解密然后校验签名的方式检验用户身份,这样就减轻了服务器的压力并加强了安全性。以上仅为Token的一种应用方式,Token更多应用于API服务。
// 设置密钥
$key = "mySecretEncryptionKey";
// 生成Token
function generateToken($userId, $key) {
$data = json_encode(["userId" => $userId, "timestamp" => time()]);
$encryptedToken = openssl_encrypt($data, 'AES-128-ECB', $key);
return $encryptedToken;
}
// 验证Token
function validateToken($token, $key) {
$decryptedData = openssl_decrypt($token, 'AES-128-ECB', $key);
if ($decryptedData) {
$data = json_decode($decryptedData, true);
if ($data && isset($data['userId']) && isset($data['timestamp'])) {
// 检查Token有效期(例如1小时)
if (time() - $data['timestamp'] < 3600) {
return "Valid token for user ID: " . htmlspecialchars($data['userId']);
} else {
return "Token has expired.";
}
}
}
return "Invalid token.";
}
$token = generateToken(123, "mySecretKey"); // 生成 Token
// 将 Token 设置在 Cookie 中
setcookie("authToken", $token, [
"expires" => time() + 3600, // 有效期1小时
"path" => "/", // 全局路径
"domain" => "", // 可以根据需要指定域
"secure" => true, // 仅通过 HTTPS 传输
"httponly" => true, // 禁止 JS 访问
"samesite" => "Strict" // 防止 CSRF 攻击
]);
// 服务器端验证 Token
if (isset($_COOKIE["authToken"])) {
$result = validateToken($_COOKIE["authToken"], "mySecretKey"); // Token 验证函数
echo $result; // 输出 Token 验证结果
}
模板及框架
为了简化开发流程,通常会用到各种模板和开发框架,开发时通过调用内置的类或函数来实现一些繁琐的功能,但是其自身也具有许多漏洞。
一、Smarty
- 模板引擎是为了让前端界面(html)与程序代码(php)分离而产生的一种解决方案,模板中包含许多tpl文件,其不能被直接访问,需要再PHP文件中传入变量后作为html代码执行。
示例
1.目录结构示例
project/
├── index.php // 主脚本
├── templates/ // Smarty 模板文件夹
│ └── example.tpl // 示例模板文件
└── templates_c/ // Smarty 编译文件夹(必须存在且可写)
2.模板文件(example.tpl
)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Smarty Example</title>
</head>
<body>
<h1>Hello, {$name}!</h1>
<p>You are {$age} years old.</p>
</body>
</html>
3.主脚本(index.php
)
// 引入 Composer 自动加载文件
require 'vendor/autoload.php';
// 创建 Smarty 实例
$smarty = new Smarty();
// 配置 Smarty 目录
$smarty->setTemplateDir('templates'); // 模板文件夹
$smarty->setCompileDir('templates_c'); // 编译文件夹
// 赋值变量
$smarty->assign('name', 'Alice');
$smarty->assign('age', 25);
// 显示模板
$smarty->display('example.tpl');
漏洞
- smarty<3.1.39存在漏洞 CVE-2021-26120
- POC:
string:{function name='x(){};system(whoami);function '}{/function}
- 漏洞原因:{function} 标签的 name 属性可以通过精心构造注入恶意代码
- 先知社区相关文章
二、ThinkPHP
- ThinkPHP是PHP的一个开发框架,其简化了许多复杂流程,其内部提供了更加安全的实现方式,例如对于SQL执行前添加了更多的字符串校验和过滤,而开发者则无需再为安全过滤重复写代码,但是这也改变或者弃用了原生的实现。
- ThinkPHP官方手册
示例
1.项目目录示例
your-project-name/
├── app/ // 应用目录
│ ├── controller/ // 控制器
│ ├── model/ // 模型
│ └── view/ // 视图
├── public/ // 公共访问目录
│ └── index.php // 入口文件
└── ...
2.视图文件
-
app/view
目录下创建index.html
ThinkPHP Example Hello, {$name}!
You are {$age} years old.
3.控制器
-
app/controller
目录下创建index.php
'Alice', 'age' => 25, ]; return View::fetch('index', $data); // 渲染视图并传递数据 } }
4.配置路由
-
route
目录下创建或编辑app/routes.php
use think\facade\Route; Route::get('/', 'Index@index'); // 将根 URL 路由到 Index 控制器的 index 方法
5.访问
-
访问
http://localhost:8000
Hello, Alice! You are 25 years old.
漏洞
- ThinkPHP < 5.0.23 远程代码执行漏洞(CVE-2018-20062),由于获取method的方法中没有正确处理方法名,导致攻击者可以调用Request类任意方法并构造利用链,从而导致远程代码执行漏洞。
- 改传参方式为Post,传入参数为"_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=pwd",其中pwd为系统执行命令可进行一系列操作。
- CSDN相关文章