php之web开发

目标

实现一款具有常用大部分功能的WEB应用,并初步了解WEB漏洞原理

登录功能:

1、基于前端的登录功能

<!DOCTYPE html>
<html>
<head>
<title>简单登录功能</title>
</head>
<meta charset="UTF-8">
<body>
<h1>登录</h1>
<form id="loginForm" οnsubmit="return login()">
<label for="username">用户名:</label>
<input type="text" id="username" required>
<br>
<label for="password">密码:</label>
<input type="password" id="password" required>
<br>
<input type="submit" value="登录">
</form>
<p id="message"></p>
​
<script>
function login() {
var username = document.getElementById("username").value;
var password = document.getElementById("password").value;
​
// 这里应该发送登录请求到服务器进行身份验证
// 在这个例子中,我们只是简单判断用户名和密码是否符合预定义值
​
// 假设正确的用户名和密码是:
var validUsername = "admin";
var validPassword = "admin";
​
if (username === validUsername && password === validPassword) {
document.getElementById("message").innerText = "登录成功!";
} else {document.getElementById("message").innerText = "登录失败,请检查用户名和密码!";
​
}
​
// 阻止表单的默认提交行为
return false;
}
</script>
</body>
</html>

效果

2、基于后端验证的登录功能

前端:

<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<head>
<title>简单登录功能</title>
</head>
<body>
<h2>登录</h2>
<form action="http://127.0.0.1/login.php" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username" required><br>
​
<label for="password">密码:</label>
<input type="password" id="password" name="password" required><br>
<input type="submit" value="登录">
</form>
</body>
</html>

后端

<meta charset="UTF-8">
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// 获取表单数据
$username = $_POST["username"];
$password = $_POST["password"];
​
// 设置硬编码的账号与密码
$validUsername = "admin";
$validPassword = "admin";
​
// 比对表单中数据
if ($username === $validUsername && $password === $validPassword) {
echo "登录成功!" . htmlspecialchars($username);
} else {
echo "登录失败,请重新登录";
}
}
?>

3、基于数据库查询的登录功能(拼接)

<meta charset="UTF-8">
<?php
$servername = "localhost";
$username = "root";
​
$password = "root";
$dbname = "demo";
​
//建立数据库连接
$conn = mysqli_connect($servername, $username, $password, $dbname);
if (!$conn) {
die("连接失败:" . mysqli_connect_error());
}
//获取表单数据
$username = $_POST["username"];
$password = $_POST["password"];
​
//我们要执行的sql语句
$sql = "SELECT password FROM users WHERE username = '$username'";
​
//绑定连接与sql语句
$result = mysqli_query($conn, $sql);
​
//判断是否存在内容
if (!$result) {
die("查询错误:" . mysqli_error($conn));
}
​
//取出查询结果
$row = mysqli_fetch_assoc($result);
​
//
if ($row) {
$hashedPassword = $row["password"];
// 验证密码
if ($password == $hashedPassword) {
// 登录成功
echo "登录成功!欢迎," . htmlspecialchars($username);
} else {
// 登录失败
echo "无效的用户名或密码,请重试。";
}
} else {
echo "用户不存在,请重试。";
}

4、基于数据库查询的登录功能(链式调用)

<meta charset="UTF-8">
<?php
class DatabaseQuery
{
private $connection;
private $sql;
​
public function __construct($connection)
{
$this->connection = $connection;
}
​
public function select($columns)
{
$this->sql .= 'SELECT '. $columns;
return $this;
}
​
public function from($table)
{
$this->sql .= " FROM $table";
return $this;
}
​
public function where($column)
{
$this->sql .= " WHERE $column";
return $this;
}
​
public function eq($value)
{
$this->sql .= " = '$value'";
return $this;
​
}
​
public function andWhere($column)
{
$this->sql .= " AND $column";
return $this;
}
​
public function execute()
{
echo $this->sql;
$result = mysqli_query($this->connection, $this->sql);
if (!$result) {
die("查询错误:" . mysqli_error($this->connection));
}
return $result;
}
}
​
// 示例使用
$servername = "localhost";
$username_db = "demo";
$password_db = "demo";
$dbname = "demo";
​
$conn = mysqli_connect($servername, $username_db, $password_db, $dbname);
if (!$conn) {
die("连接失败:" . mysqli_connect_error());
}
$username = $_POST["username"];
$password = $_POST["password"];
​
$dbQuery = new DatabaseQuery($conn);
$result = $dbQuery->select('username')
->from('users')
->where('password')->eq($password)
->execute();
​
if (!$result) {
​
die("查询错误:" . mysqli_error($conn));
}
​
while ($row = mysqli_fetch_assoc($result)) {
echo "Username: " . $row['username'] . "<br>";
}
​
mysqli_close($conn);
?>

5、基于数据库查询的登录功能(预编译)

<meta charset="UTF-8">
<?php
if ($_SERVER["REQUEST_METHOD"] === "POST") {
// 从表单中获取用户名和密码
$username = $_POST["username"];
$password = $_POST["password"];
​
// 连接到MySQL数据库
$conn = new mysqli("localhost", "root", "root", "demo");
if ($conn->connect_error) {
die("连接失败: " . $conn->connect_error);
}
​
// 准备SQL查询语句
//设置空位
$stmt = $conn->prepare("SELECT password FROM users WHERE username = ?");
// 将参数插入空位
$stmt->bind_param("s", $username);
// 执行sql语句
$stmt->execute();
// 将结果进行绑定
$stmt->bind_result($hashedPassword);
​
// 刷新
$stmt->fetch();
​
// 验证密码
if ($password === $hashedPassword) {
// 登录成功
echo "登录成功!欢迎," . htmlspecialchars($username);
// 在此处可以执行其他操作或重定向到另一个页面
} else {
// 登录失败
echo "无效的用户名或密码,请重试。";
// 在此处可以重定向回登录页面或显示错误消息
}
​
// 关闭语句和连接
$stmt->close();
$conn->close();
}
?>
​

控制访问功能:

使用cookie实现访问控制

// 设置一个时间
$expire = time() + 3600;
​
// 设置一个cookie
setcookie("user", $username, $expire, "/");
​
// 登录成功后,可以跳转到其他页面
header("Location: admin.php");
exit();
​
​
<meta charset="UTF-8">
<?php
1if ($_COOKIE["user"] === 'admin') {
// 用户已登录,可以允许访问受保护的内容
echo '欢迎来到后台';
} else {
// 用户未登录,可能跳转到登录页面或显示登录提示
header("Location: login.html");
}

使用session实现访问控制

$username = "user123";
// 开启会话
session_start();
// 设置会话数据
$_SESSION['user'] = $username;
// 登录成功后,可以跳转到其他页面
header("Location: welcome.php");
exit();
​
<meta charset="UTF-8">
<?php
session_start();
// 设置会话数据
if ($_SESSION['user'] === 'admin') {
// 用户已登录,可以允许访问受保护的内容
echo '欢迎来到后台';
} else {
// 用户未登录,可能跳转到登录页面或显示登录提示
header("Location: login.html");
}

上传功能:

前端:

<!DOCTYPE html>
<html>
<head>
<title>文件上传</title>
</head>
<body>
<h2>上传文件</h2>
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="上传" name="submit">
</form>
</body>
</html>

后端:

<?php
if (isset($_POST["submit"])) {
$targetDir = "uploads/"; // 上传文件存储目录,确保该目录存在并有写入权限
$targetFile = $targetDir . basename($_FILES["fileToUpload"]["name"]);
$uploadOk = 1;
$imageFileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION));// 检查文件是否是一个真实的文件
if (isset($_FILES["fileToUpload"])) {
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
if ($check === false) {
echo "文件不是一个图片。";
$uploadOk = 0;
}
}// 检查文件是否已存在
if (file_exists($targetFile)) {
echo "文件已存在。";
$uploadOk = 0;
}// 允许的文件类型(这里假设只允许上传图片)
$allowedTypes = array("jpg", "jpeg", "png", "gif");
if (!in_array($imageFileType, $allowedTypes)) {
echo "只允许上传 JPG, JPEG, PNG, GIF 格式的文件。";
$uploadOk = 0;
}// 检查文件大小(这里设置最大文件大小为5MB)
$maxFileSize = 5 * 1024 * 1024; // 5 MB
if ($_FILES["fileToUpload"]["size"] > $maxFileSize) {
echo "文件大小超过限制(5MB)。";
$uploadOk = 0;
}// 检查上传过程中是否发生错误
if ($uploadOk == 0) {
echo "文件上传失败。";
} else {
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) {
echo "文件上传成功。";
} else {
echo "文件上传失败。";
}
}
}
?>

其他文件写入函数:

在 PHP 中,文件写入可以使用以下类函数和方法:

1.file_put_contents(): 该函数在之前已经提到过,它既可以用作函数,也可以用作类方法。作为类方法时,它用于将内容写入文件。

示例如下:

$file = 'path/to/file.txt';
$data = 'Hello, World!';if (file_put_contents($file, $data) !== false) {
echo "文件写入成功!";
} else {
echo "文件写入失败!";
}

2.fwrite(): 这是一个底层的文件写入方法。它需要使用文件句柄来打开文件,并将数据写入。

示例如下

$file = 'path/to/file.txt';
$data = 'Hello, World!';$fileHandle = fopen($file, 'w');
if (fwrite($fileHandle, $data) !== false) {
echo "文件写入成功!";
} else {
echo "文件写入失败!";
}
fclose($fileHandle);

3.SplFileObject: 这是一个内置的 PHP 类,用于处理文件。它提供了许多文件操作的方法,包括读取和写入文件。

示例如下:

$file = new SplFileObject('path/to/file.txt', 'w');
$data = 'Hello, World!';$file->fwrite($data);
// 或者使用迭代器方式写入多行数据$dataArray = array('Line 1', 'Line 2', 'Line 3');
foreach ($dataArray as $line) {
$file->fwrite($line . PHP_EOL);
}
$file = null; // 关闭文件

4.fputs(): 这是与

fwrite() 函数功能相似的另一个底层文件写入函数。示例如下:

$file = 'path/to/file.txt';
$data = 'Hello, World!';$fileHandle = fopen($file, 'w');
if (fputs($fileHandle, $data) !== false) {
echo "文件写入成功!";
} else {
echo "文件写入失败!";
}
fclose($fileHandle);

文件解压:

解压 Zip 文件:

function unzipFile($zipFile, $extractToDir) {
$zip = new ZipArchive();if ($zip->open($zipFile) === true) {
// 创建目标文件夹(如果不存在)
if (!is_dir($extractToDir)) {
mkdir($extractToDir, 0755, true);}// 解压缩文件
$zip->extractTo($extractToDir);
$zip->close();echo '解压缩成功!';
} else {
echo '解压缩失败!';
}
1}$zipFile = 'path/to/archive.zip';
$extractToDir = 'path/to/extracted_folder/';
unzipFile($zipFile, $extractToDir);

解压 Tar 文件

function untarFile($tarFile, $extractToDir) {
try {
$phar = new PharData($tarFile);
$phar->extractTo($extractToDir, null, true);echo '解压缩成功!';
} catch (Exception $e) {
echo '解压缩失败:' . $e->getMessage();
}
}$tarFile = 'path/to/archive.tar';
$extractToDir = 'path/to/extracted_folder/';
untarFile($tarFile, $extractToDir);

文件读取:

PHP 提供了多个函数用于文件读取。以下是一些常用的文件读取函数:

1.file_get_contents(): 用于将整个文件内容读取为一个字符串。

$file = 'path/to/file.txt';
$content = file_get_contents($file);

2.file(): 将文件内容读取为一个数组,其中每一行都是数组的一个元素。

$file = 'path/to/file.txt';
$lines = file($file);

3.fopen(): 这些是底层的文件读取函数,允许你以更细粒度的方式控制文件的读取。

$file = 'path/to/file.txt';
$handle = fopen($file, 'r');
$content = fread($handle, filesize($file));
fclose($handle);

4.fgets(): 逐行读取文件内容。

$file = 'path/to/file.txt';
$handle = fopen($file, 'r');
while (!feof($handle)) {
$line = fgets($handle);
echo $line;
}
fclose($handle);

5.fgetc(): 逐字符读取文件内容。

$file = 'path/to/file.txt';
$handle = fopen($file, 'r');
while (!feof($handle)) {
$char = fgetc($handle);
echo $char;
}
fclose($handle);

6.SplFileObject: 这是一个内置的 PHP 类,用于处理文件。它提供了许多文件操作的方法,包括逐行读取和随机访问。

$file = new SplFileObject('path/to/file.txt', 'r');
while (!$file->eof()) {
$line = $file->fgets();
echo $line;
}
$file = null; // 关闭文件

文件读取2:

1.file_get_contents()

这个函数可以用于读取文件内容,也可以用于从URL中读取内容。如果未正确验证和过滤用户提供的URL,攻击者可以通过构造恶意URL来进行SSRF攻击。

<?php
$url = $_GET['url'];
$content = file_get_contents($url);
echo $content;
?>

2.curl_exec()

cURL是一个用于进行各种网络请求的强大工具,但如果未正确验证和限制用户提供的URL,它也可能被用于发起SSRF攻击。

<?php
$url = $_GET['url'];$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);echo $response;
?>

3.fopen()

这个函数用于打开文件或URL。如果攻击者可以控制URL参数,并且服务器上执行了读取操作,那么可能导致SSRF。

<?php
$url = $_GET['url'];
$file = fopen($url, 'r');
echo fread($file, filesize($url));
fclose($file);
?>

4.fsockopen()

函数用于在 PHP 中打开一个网络连接,可以用于与服务器进行通信

<?php
$url = $_GET['url'];
$port = 80;$parts = parse_url($url);
if (!$parts || !isset($parts['host'])) {
die("Invalid URL");
}$host = $parts['host'];
$path = isset($parts['path']) ? $parts['path'] : '/';
$query = isset($parts['query']) ? '?' . $parts['query'] : '';$fp = fsockopen($host, $port, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET $path$query HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";fwrite($fp, $out);while (!feof($fp)) {
echo fgets($fp, 128);
}fclose($fp);
}
?>

文件删除:

PHP 中有几个用于文件删除的函数,可以根据不同的需求和场景选择合适的函数。以下是一些常见的用于文件删除的 PHP 函数:

1.unlink(): 函数用于删除文件。

<?php
$file_path = 'path/to/file.txt';
if (file_exists($file_path)) {
unlink($file_path);
echo "删除成功.";
} else {echo "删除失败.";
}
?>

2.rmdir():函数用于删除一个空目录。

<?php
$dir_path = 'path/to/empty_directory';
if (is_dir($dir_path)) {
rmdir($dir_path);
echo "删除成功.";
} else {
echo "删除失败.";
}
?>

模块加载:

function add_modules($mod){
$classFile = __DIR__ . '/../modules/' . $mod; 
if (file_exists($classFile)) {
require_once($classFile); }else{
echo "模块不存在"; }
}

XML:

<!DOCTYPE ANY [ 
<!ENTITY xxe SYSTEM "file:///C:/Users/Administrator/Desktop/1.txt">
]>
<root>
<foo>&xxe;</foo>
</root>

1.SimpleXML:

SimpleXML 扩展提供了一种简单的方式来解析 XML 数据并将其转换为对象。它允许你通过属性和方法访问 XML 元素和属性。

在PHP里面,解析xml用的是libxml,其在≥2.9.0的版本中,默认是禁止解析xml外部实体内容的。

<?
error_reporting(0);
libxml_disable_entity_loader(false);
$xml = file_get_contents('php://input');
$loadOptions = LIBXML_NOENT | LIBXML_NOERROR | LIBXML_NOWARNING;$doc = simplexml_load_string($xml, 'SimpleXMLElement', $loadOptions);if ($doc !== false) {
echo $doc->title; // 输出展开实体引用后的 XML
} else {
echo "XML 解析出错。";
}

2.DOMDocument

DOMDocument 类提供了一种更底层的方式来解析和操作 XML 文档。它以 DOM(文档对象模型)表示 XML 文档,允许你使用节点、元素和属性进行操作。

<?
error_reporting(0);
libxml_disable_entity_loader(false);
$xml = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
$foo = $creds->foo;
echo $foo;
LIBXML_NOENT:这个选项表示在解析XML时不要展开实体引用。实体引用是以&开头的字符序列,比如&amp;
表示&,&lt;表示<等。
设置这个选项后,解析器不会将实体引用展开为相应的字符。
LIBXML_DTDLOAD:这个选项表示解析器在解析XML时要加载和处理文档类型定义(DTD)。
DTD是一种定义XML文档结构的语法,它描述了元素、属性等的规则。设置了这个选项,解析器会尝试加载并
解析文档中的DTD部分。

3.XMLReader:

XMLReader 类提供了一种基于事件的方式来解析大型 XML 文档。它逐步读取 XML 数据,并通过触发事件来处理节点、元素和属性。

<?
error_reporting(0);
libxml_disable_entity_loader(false);
$xml = file_get_contents('php://input');
$reader = new XMLReader();
$reader->xml($xml);
// 设置解析器属性以展开实体引用$reader->setParserProperty(XMLReader::SUBST_ENTITIES,
true);while ($reader->read()) {
if ($reader->nodeType == XMLReader::ELEMENT) {
$node = $reader->expand();if ($node->nodeType == XMLReader::ELEMENT) {
echo "Text: " . $node->textContent . "\n";
}
}
}

序列化:

<?phpclass User {public $privilege; 
public $id; 
public $attribute; public function __construct($privilege, $id)
{
$this->privilege = $privilege; 
$this->id = $id; 
}public function get_permissions(){
if($this->privilege->get_name == 'admin'){
echo '你是admin用户'; die(); }
elseif($this->privilege->get_name == 'guest'){
echo '你是guest用户'; die(); }
}public function get_permissions_attribute(){
$attribute = $this->attribute; 
echo $this->privilege->$attribute; }public function __wakeup()
{
$this->get_permissions(); 
if(!empty($this->attribute)){
$this->get_permissions_attribute(); }
}}class Base{
public function get($name)
{
echo "未找到: {$name}方法"; }
}class shell{
public $cmd; 
public function __get($name)
{
echo $name; }
public function __toString()
{
return system($this->cmd); 
}
}ini_set('display_errors', 'on');
unserialize($_POST['user']);
?>

答案1:

<?php
class User {public $privilege; public $id; public $attribute; public function __construct($privilege, $id){
$this->privilege = $privilege; $this->id = $id; }public function get_permissions(){
if($this->privilege->get_name == 'admin')
{
echo '你是admin用户'; die(); 
}
elseif($this->privilege->get_name == 'guest'){
echo '你是guest用户'; die(); 
}
}public function get_permissions_attribute(){
$attribute = $this->attribute; 
echo $this->privilege->$attribute; }
public function __wakeup()
{
$this->get_permissions(); if(empty($this->attribute)){
$this->get_permissions_attribute($this->attribute); }}}class Admin {
public $name = 'admin'; public $describe = '当前用户为管理员权限,可以登录后台'; 
public $Base; public function __construct(){
$this->Base = new Base(); }public function __get($name)
{
$this->Base->get($name); }}class Guest {
public $name = 'guest'; public $describe = '当前用户为访客权限,无法登录后台'; 
public $Base; public function __construct(){
$this->Base = new Base(); }public function __get($name)
{
$this->Base->get($name); }}class Base{
public function get($name)
{
echo "未找到: {$name}方法"; }}class shell{
public $cmd = 'calc'; public function __get($name)
{
system($this->cmd); }public function __toString()
{
return eval($this->cmd); }}$shell = new shell();$user = new user($shell, 1);?>

JSON:

在 PHP 中,你可以使用多种类和方法来解析 JSON 数据。以下是一些常用的类和方法:

1.json_decode():

这是 PHP 内置的函数,用于将 JSON 字符串解析为 PHP 数组或对象。它是最常用的 JSON 解析方法。

$jsonString = '{"name":"Alice","age":30}';
$data = json_decode($jsonString, true); // 解析为关联数组
// 或者
$data = json_decode($jsonString); // 解析为对象

2.json_encode():

$data = ['name' => 'Alice', 'age' => 30];
$jsonString = json_encode($data);

3.解析 JSON 对象:

将 JSON 字符串解析为 PHP 对象或数组。

$jsonString = '{"name":"Alice","age":30,"email":"alice@example.com"}';
$person = json_decode($jsonString);
echo $person->name; // 输出: Alice

4.访问 JSON 对象的属性:

在解析后的 PHP 对象中,你可以使用箭头运算符 -> 来访问 JSON 对象的属性。

echo $person->age; // 输出: 30
echo $person->email; // 输出: alice@example.com

5.嵌套 JSON 对象:

JSON 对象可以包含其他 JSON 对象作为属性。

$person = [
'name' => 'Alice',
'contact' => [
'email' => 'alice@example.com',
'phone' => '123-456-7890'
]
];$jsonString = json_encode($person);

6.设置选项:

使用json_encode函数的第二个参数可以设置 JSON 输出的选项,如缩进和 Unicode 转义。

$jsonString = json_encode($person, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);

XSS:

<img src=x οnerrοr="alert(/xss/)">

前端

function showMessageList() {
// 获取留言列表
fetch('/api/get_message.php')
.then(response => response.json())
.then(data => {
messageContainer.innerHTML = '';
data.forEach(message => {
const messageDiv = document.createElement('div');
// messageDiv.textContent = `User: ${message.username}, Message:
${message.content}`;messageDiv.innerHTML = `User: ${message.username}, Message:
${message.content}`;messageContainer.appendChild(messageDiv);
//messageContainer.append(messageDiv);
});
});
}
function showMessageList() {
// 获取留言列表
fetch('/api/get_message.php')
.then(response => response.json())
.then(data => {
messageContainer.innerHTML = '';
data.forEach(message => {
const messageDiv = document.createElement('div');// 使用纯文本节点来避免解释 JavaScript 代码
const usernameTextNode = document.createTextNode(`User:
${message.username}`);messageDiv.appendChild(usernameTextNode);// 将 message.content 添加到 messageDiv
const contentTextNode = document.createTextNode(`, Message:
${message.content}`);messageDiv.appendChild(contentTextNode);// 将 messageDiv 添加到页面
messageContainer.appendChild(messageDiv);
});
});

后端

在 PHP 中,有一些函数可以帮助您防止跨站脚本(XSS)漏洞。这些函数可以用于在将用户输入嵌入

到 HTML、JavaScript、CSS 或其他上下文中时,对输入进行适当的转义或过滤。以下是一些常用的

防止 XSS 漏洞的函数:

1.htmlspecialchars:

用于将特殊字符转义为 HTML 实体,从而防止恶意脚本的执行。它是防止在 HTML 上下文中的 XSS

攻击的首选方法。

$escapedInput = htmlspecialchars($userInput, ENT_QUOTES, 'UTF-8');

2.strip_tags:

$cleanInput = strip_tags($userInput);

3.htmlentities:

$escapedInput = htmlentities($userInput, ENT_QUOTES, 'UTF-8');

4.filter_var:

通过过滤器进行输入验证和过滤,可以用于过滤特定类型的输入,如 URL、邮箱等。

$filteredInput = filter_var($userInput, FILTER_SANITIZE_STRING);

5.JavaScript Escape:

$jsEscapedInput = json_encode($userInput);
// 或者
$jsEscapedInput = addslashes($userInput);

6.Content Security Policy (CSP):

不是一个函数,而是一种更全面的安全策略,通过设置 HTTP 头来限制允许加载的资源来源,从而减

少 XSS 攻击的风险。

Content Security Policy(CSP)是一种在网页中实施的安全策略,用于减少跨站脚本(XSS)等安全

威胁。CSP 允许您指定哪些内容可以加载到页面中,从而减少恶意代码的执行。

要使用 Content Security Policy,您需要在您的网页的 <head> 部分添加一个 meta 标签或通过 HTTP

头来指定策略。以下是一个简单的示例:

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src
'self'<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src
'self'<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src
'self'
<title>My Secure Website</title>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>

在上面的示例中,Content-Security-Policy 头通过 meta 标签指定了一些策略规则:

  • default-src 'self'

  • script-src 'self' TransIP - Reserved domain TransIP - Reserved domain

  • style-src 'self' https://trusted-styles.com https://trusted-styles.com

这是一个基本示例,您可以根据您的应用程序需求进行调整。策略规则包括 default-src、script-src、style

src、img-src、font-src 等,您可以根据需要进行设置。

请注意,实施 CSP 可能会对您的应用程序的一些功能产生影响,特别是在使用第三方脚本或资源时。

7.禁止 JavaScript 获取 cookie

在 PHP 中,setcookie 函数的参数用于设置 Cookie 的各种属性。以下是每个参数的含义:

setcookie(
string $name, //Cookie 的名称。
string $value = "", //Cookie 的名称。int $expire = 0, // Cookie 的过期时间,以 UNIX 时间戳表示。如果设置为 0,或省略该参数,则
Cookie 会在会话结束后过期。string $path = "", // Cookie 的过期时间,以 UNIX 时间戳表示。如果设置为 0,或省略该参数,
则 Cookie 会在会话结束后过期。string $domain = "", // Cookie 的过期时间,以 UNIX 时间戳表示。如果设置为 0,或省略该参
数,则 Cookie 会在会话结束后过期。bool $secure = false, // Cookie 的过期时间,以 UNIX 时间戳表示。如果设置为 0,或省略该参
数,则 Cookie 会在会话结束后过期。bool $httponly = false //如果设置为 true,则 JavaScript 无法通过 document.cookie 访问
该 Cookie,增加安全性(HttpOnly 标志)。)

CSRF:

前端:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Form with JSON and CORS</title>
</head>
<body>
<h1>Login Form with JSON and CORS</h1>
<div>
<label for="username">Username:</label>
<input type="text" id="username" required><br><br>
<label for="password">Password:</label>
<input type="password" id="password" required><br><br>
<button id="loginButton">Login</button>
</div>
<div id="loginMessage"></div><script>
const loginButton = document.getElementById('loginButton');
const loginMessage = document.getElementById('loginMessage');loginButton.addEventListener('click', () => {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;const loginData = {
username: username,
password: password
};fetch('http://qqx.com/api/cors.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},body: JSON.stringify(loginData)
})
.then(response => {
if (!response.ok) {
throw new Error('Login failed');
}
return response.json();
})
.then(data => {
loginMessage.textContent = 'Login successful!';
loginMessage.style.color = 'green';
})
.catch(error => {loginMessage.textContent = 'Login failed. Please check your credentials.';
loginMessage.style.color = 'red';
});
});
</script>
</body>
</html>

结果

<?phpecho 1111;
header("Access-Control-Allow-Origin: http://qqx.com");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
header("Access-Control-Allow-Credentials: true");

触发条件:

浏览器在发起跨域请求时,会在需要的情况下发起预检请求(OPTIONS请求)来验证服务器是否允许

实际请求的跨域访问。这个预检请求的主要目的是检查服务器是否设置了合适的CORS头部,以确定是

否允许实际请求(如GET、POST)跨域访问。

预检请求通常在以下情况下发起:

  1. 使用非简单请求方法:当浏览器在跨域情况下使用非简单请求方法(如PUT、DELETE、自定义头部等)时,它会发起预检请求来验证服务器是否允许这种请求。

  2. 自定义请求头部:如果请求中包含了自定义的HTTP头部,浏览器可能会发起预检请求来确保服务器允许这些自定义头部。

以下是浏览器发起预检请求(OPTIONS请求)的一般流程:

  1. 浏览器检测到跨域请求,检查请求是否满足“简单请求”的条件,如果满足则直接发送实际请求。

  2. 如果请求不满足“简单请求”的条件,浏览器会自动发送一个OPTIONS请求,请求的头部中会包含一些预检信息,如请求方法、请求头部等。

  3. 服务器收到OPTIONS请求后,需要正确地设置CORS头部,如Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers 等。服务器需要返回适当的CORS头部,以告诉浏览器是否允许实际请求的跨域访问。

4.如果服务器的CORS头部允许跨域访问,浏览器会继续发送实际请求,如果不允许,则浏览器会拒绝发送实际 请求,遵循同源策略。

需要注意的是,服务器需要正确处理OPTIONS请求,并在响应中设置适当的CORS头部,以使浏览器

能够理解是否允许跨域访问。预检请求是CORS机制的一部分,有助于确保安全的跨域资源访问。

请求类型:

CORS(跨源资源共享)规范将HTTP请求分为两种类型:简单请求和非简单请求。简单请求(Simple

Request)满足一组特定的条件,不会触发预检请求(OPTIONS请求)。而非简单请求(Non-Simple Request)则需要在发起实际请求之前进行预检请求,以确定服务器是否允许跨域访问。

以下是被认为是非简单请求方法的一些常见HTTP方法:

用于向服务器提交数据,修改服务器上的资源。

用于请求服务器删除指定的资源。

用于对服务器上的资源进行部分更新。

用于建立网络连接,通常在代理服务器上使用。

用于请求有关服务器支持的请求方法和HTTP头部信息的信息。

触发条件:

使用非简单请求方法:当浏览器在跨域情况下使用非简单请求方法(如PUT、DELETE、自定义头部等)时,它会

发起预检请求来验证服务器是否允许这种请求。

自定义请求头部:如果请求中包含了自定义的HTTP头部,浏览器可能会发起预检请求来确保服务器允许这些自

定义头部。

浏览器检测到跨域请求,检查请求是否满足“简单请求”的条件,如果满足则直接发送实际请求。

如果请求不满足“简单请求”的条件,浏览器会自动发送一个OPTIONS请求,请求的头部中会包含一些预检信

息,如请求方法、请求头部等。

服务器收到OPTIONS请求后,需要正确地设置CORS头部,如

如果服务器的CORS头部允许跨域访问,浏览器会继续发送实际请求,如果不允许,则浏览器会拒绝发送实际请

求,遵循同源策略。

请求类型:

  1. PUT:

    用于向服务器提交数据,修改服务器上的资源。

  2. DELETE:

    用于请求服务器删除指定的资源。

  3. PATCH:

    用于对服务器上的资源进行部分更新。

  4. CONNECT:

    用于建立网络连接,通常在代理服务器上使用。

  5. OPTIONS:

    用于请求有关服务器支持的请求方法和HTTP头部信息的信息。

  6. TRACE:

用于在路径上执行一个消息环回测试,以诊断路径中的问题。

后端

1.设置响应头部信息:

在您的PHP脚本中,可以通过设置响应头部来控制CORS策略。以下是一些常见的响应头部字段,您可以根据需要进行设置:

header("Access-Control-Allow-Origin: *"); // 允许所有来源访问,或替换为具体的域名
header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); // 允许的HTTP方法
header("Access-Control-Allow-Headers: Content-Type"); // 允许的请求头
header("Access-Control-Allow-Credentials: true"); // 如果需要使用跨域的Cookie,设置为true

2.使用预检请求(Preflight Requests):

对于一些复杂的跨域请求(例如带有自定义头部的POST请求),浏览器会首先发送一个预检请求

(OPTIONS请求)以验证服务器是否支持跨域请求。您需要在服务器上处理这些预检请求并返回适当

的响应头部。例如:

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
header("Access-Control-Allow-Credentials: true");
header("HTTP/1.1 204 No Content");
exit();
}

3.验证来源和请求头部:

在您的PHP脚本中,您可以根据需要对请求来源进行验证,以确保只有合法的来源可以访问您的资

源。例如:

$allowedOrigins = array("https://example.com", "https://anotherdomain.com");
$origin = $_SERVER['HTTP_ORIGIN'];if (in_array($origin, $allowedOrigins)) {
header("Access-Control-Allow-Origin: " . $origin);
header("Access-Control-Allow-Methods: GET, POST");
// 其他头部设置
} else {
// 处理非法来源
1header("HTTP/1.1 403 Forbidden");
exit();
1}

JSONP:

JSONP 的工作原理是通过在页面中动态创建 <script> 标签,从而允许跨域资源被加载。因为 <script> 标签的跨域限制比较宽松,它不受同源策略的限制。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONP Example</title>
</head>
<body>
<h1>JSONP Example</h1>
<div id="dataContainer"></div>
<script>
function handleJSONPResponse(data) {
const dataContainer = document.getElementById('dataContainer');
dataContainer.textContent = 'Response from JSONP: ' + JSON.stringify(data);
}// Create a script element to make the JSONP request
const script = document.createElement('script');
script.src = 'http://qqx.com/demo2.php?callback=handleJSONPResponse';
document.body.appendChild(script);
</script>
</body>
</html>

<?php
$data = array("name" => "John", "age" => 30);
$callback = $_GET['callback']; // 获取callback参数
// 输出带有回调函数的响应
echo $callback . '(' . json_encode($data) . ');';
?>

蜜罐:

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JSONP Example</title>
</head>
<body>
<h1>JSONP Example</h1>
<div id="dataContainer"></div><script>
function handleJSONPResponse(data) {
const dataContainer = document.getElementById('dataContainer');
dataContainer.textContent = 'Response from JSONP: ' + JSON.stringify(data);// 定义要发送的数据
const jsonp = {
key1: "1",
key2: "value2"
};// 发起POST请求
fetch("http://127.0.0.1:8000/?a="+JSON.stringify(data), {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(jsonp)
})
.then(function(response) {
if (response.ok) {
// 请求成功,处理响应数据
return response.json();
} else {
// 请求失败,处理错误
throw new Error("Network response was not ok");
}
})
.then(function(data) {
console.log(data);
}).catch(function(error) {
console.error("There was a problem with the fetch operation:", error);
});}// Create a script element to make the JSONP request
const script = document.createElement('script');
script.src = 'http://qqx.com/demo2.php?callback=handleJSONPResponse';
document.body.appendChild(script);
</script>
</body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/18054.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python】 Python中的“命名元组”:简单而强大的数据结构

基本原理 在Python中&#xff0c;namedtuple是tuple的一个子类&#xff0c;它允许我们为元组的每个位置指定一个名字。这种数据结构非常适合用于需要固定字段和值的场景&#xff0c;例如数据库查询的结果或配置文件中的设置。 namedtuple提供了一种方便的方式来访问元组中的元…

海外盲盒系统APP开发,盲盒出海热潮下的蓝海

近几年&#xff0c;我国潮玩出海成为了一个的大风口。根据数据显示&#xff0c;今年全球潮玩规模将达到400多亿美元&#xff0c;市场发展空间巨大。海外庞大的市场对于我国盲盒出海是一个较大的优势。在当下互联网的快速发展下&#xff0c;海外盲盒APP商城成为了盲盒企业出海的…

开源VS闭源:谁将引领AI大模型的新时代?

一、引言 随着人工智能技术的飞速发展&#xff0c;AI大模型已成为推动这一浪潮的核心动力。在AI大模型的发展过程中&#xff0c;开源与闭源两种不同的发展路径一直备受关注。本文将深入探讨这两种路径的优劣势&#xff0c;分析它们对AI大模型发展的影响&#xff0c;并预测谁将…

ctfshow web入门 黑盒测试

web380 这里文章看的我好有感触 但是影响做题 扫描一下 访问flag.php啥也没有再访问page.php page.php?idflagweb381 扫出来page.php但是没啥用哇&#xff0c;查看源代码 这些文件挨个试发现啥也没&#xff0c;最后仔细对比发现其实都是layui&#xff0c;然后尝试着访问…

《架演》共创者第一次线上沟通会议总结

《架演》共创者第一次线上沟通——启动会 会议主题&#xff1a;《架演》共创启动会议会议时间&#xff1a;2024年5月28日&#xff0c;20:00 - 21:00会议地点&#xff1a;腾讯会议主持人&#xff1a;寒山参会人员&#xff1a; 夏军、mirror、刘哥、悟缺席人员&#xff1a;可心、…

Cocos Creator 安卓环境配置

系统&#xff1a;Win10&#xff0c;引擎版本&#xff1a;CocosCreator3.8.2&#xff0c; 时间&#xff1a;2024.05.23 安装 Java SDK(JDK)下载地址 注意&#xff1a;Java版本对应的Gradle: 详见表 Table 1. Java Compatibility 此处选择 Java 21 对应 Gradle 8.5 配置Java系统…

2024.05.22学习记录

1、面经复习&#xff1a; Vue组件通讯、vuex、js严格模式、options请求、vue3 Setup 语法糖、React hook 2、代码随想录刷题&#xff1a;动态规划 3、rosebush组件库 完成Alert和Alert测试 Menu组件初步开发

RocketMQ 主从复制原理深度解析

提到主从复制&#xff0c;我们可能立马会联想到 MySQL 的主从复制。 MySQL 主从复制是 MySQL 高可用机制之一&#xff0c;数据可以从数据库服务器主节点复制到一个或多个从节点。 这篇文章&#xff0c;我们聊聊 RocketMQ 的主从复制&#xff0c;希望你读完之后&#xff0c;能…

文献解读-群体基因组第一期|《对BMI的影响:探究BMI的基因型-环境效应》

关键词&#xff1a;应用遗传流行病学&#xff1b;群体测序&#xff1b;群体基因组&#xff1b;基因组变异检测&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;The Impact of ACEs on BMI: An Investigation of the Genotype-Environment Effects of BMI标…

knex与sequelize 以及断点工具使用

knex 使用 SQL Query Builder for Javascript | Knex.js 首先下载 npm install knex 使用 const knex require(knex)({client: mysql,connection: {host: localhost, // 地址user: root, // 账号password: 123456, // 密码database: user // 数据库}});/*** kn…

React-组件基础使用

组件是什么 概念&#xff1a;一个组件就是用户界面的一部分&#xff0c;它可以有自己的逻辑和外观&#xff0c;组件之间可以互相嵌套&#xff0c;也可以复用多次 组件化开发可以让开发者像搭积木一样构建一个完整的庞大的应用 React组件 在React中&#xff0c;一个组件就是首…

云动态摘要 2024-05-24

给您带来云厂商的最新动态&#xff0c;最新产品资讯和最新优惠更新。 最新优惠与活动 [免费试用]大模型知识引擎体验招募 腾讯云 2024-05-21 大模型知识引擎产品全新上线&#xff0c;为回馈新老客户&#xff0c;50万token免费送&#xff0c;开通服务即领取&#xff01; 云服…

git教程(IDEA + 命令行)

首先假设你已经安装 git 且 已经初始化完成&#xff1a; // 初始化git config --global user.name "你的用户名" git config --global user.email "你的邮箱"在当前文件夹下创建一个仓库&#xff0c;且该文件夹下会有多个项目 首先在当前文件夹下新建git…

微信小程序毕业设计-校园综合服务系统项目开发实战(附源码+论文)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;微信小程序毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计…

VSCode开发Python-Django入门

一、安装配置Python环境及配置Python环境变量 1、python安装包安装后&#xff0c;需要注意pip.exe和pip3.exe的安装&#xff1b; 2、环境变量需要配置两个目录&#xff1b; 3、验证python是否安装成功 通过cmd命令执行&#xff1a;python --version 查看python版本&#xff…

高中生是否需要上电子阅览室

高中生是否需要上电子阅览室&#xff0c;取决于学生的学习需求和个人喜好。以下是一些考虑因素&#xff1a; 1. 便利性&#xff1a;电子阅览室通常提供电脑设备和网络连接&#xff0c;方便学生在线获取学习资源。对于家中没有电脑或者网络不稳定的学生&#xff0c;上电子阅览室…

实战

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 实战一&#xff1a;模拟支付宝蚂蚁森林的能量产生过程 支付宝的蚂蚁森林通过日常的走步、生活缴费、线下支付、网络购票、共享单车等低碳、环保行为…

java函数编程-黑马学习笔记

第一章 01合格的函数 函数就是一个规则 合格的函数就是只要你输入相同&#xff0c;无论多少次调用&#xff0c;不论什么时间调用&#xff0c;输出是相同的。 函数可以引用外部的数据&#xff0c;但是需要去保证外部的数据不可变 static关键字修饰的静态方法本质上和函数没…

XDebug配置几件教程,phpstorm实现http请求断点调试

写这篇的文章的初衷:网络上配置XDebug的文章有很多,XDebug也有官方的文档, PhpStorm也有官方的文档,为什么还要写那? 相信不少人,都有一种感觉,虽然教程很多,但是按教程走一遍,自己的确不能正常调试。 问题出在下面几个方面: 1. 对调试过程中,没有一定的认识,因此…

HBase分布式数据库入门到精通

文章目录 HBase分布式数据库入门到精通 一、简单介绍 二、HBase数据模型 三、HBase的架构 四、HBase写操作流程 五、HBase读操作流程 六、HBase minor小合并和major大合并 七、HBase目标表meta表 八、HBase特点 九、HBase的使用场景 HBase分布式数据库入门到精通 一、…