Cookie&Session&Token

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相关文章
上一篇
下一篇