php之web开发

news2024/12/28 6:07:33

目标

实现一款具有常用大部分功能的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";
}
}
}

序列化:

<?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(); }
}

}

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>

结果

<?php

echo 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.coloradmin.cn/o/1684545.html

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

相关文章

yaml文件格式详解 及 k8s实战演示

目录 一 k8s 支持的语言格式 1&#xff0c;YAML 语法格式 2&#xff0c;查看 api 资源版本标签 二 k8s 运行nginx pod实例 yaml文件 具体讲解 1&#xff0c;写一个yaml文件demo 2&#xff0c;deployment 管理nginx 的yaml 文件 3&#xff0c;创建资源对象 4&#…

BGP(一)边界网关协议

BGP协议基础 路由分类 直连路由 非直连路由&#xff08;间接路由&#xff09; 静态路由动态路由 IGP&#xff1a;内网网关路由协议&#xff08;在企业内部或数据中心内部使用&#xff09; DV&#xff1a;距离矢量路由协议RIP&#xff08;v1/v2&#xff09;IGRP——网络直径&…

【超全干货】一文讲清什么是全民分销?怎么做好全民分销?

一、什么是全民分销&#xff1f; 全民分销&#xff0c;作为新时代营销模式的代表之一&#xff0c;是基于互联网尤其是社交媒体平台兴起的一种分销策略。它打破了传统零售与电子商务的界限&#xff0c;允许任何个人&#xff0c;无论是否为专业销售人员&#xff0c;都能成为品牌…

JJJ:ubuntu修改静态ip

一、IP变化的原因 1.DHCP协议 虚拟机系统(Ubuntu、CentOS、UOS等Linux系统)启动后&#xff0c;加入本地局域网网络时&#xff0c;会向本地网络申请租约一个IP地址&#xff0c;租约时长不定。我这里租约时间短到只有1小时左右就更换一次IP地址。 二、解决方法&#xff1a;手动…

英语学习笔记20——Look at them!

Look at them! 看看他们&#xff01; 词汇 Vocabulary big a. 大的&#xff08;尺寸&#xff0c;年龄&#xff0c;音量……&#xff09; 搭配&#xff1a;big cheese 大人物    big mouth 大嘴巴&#xff08;传话的人&#xff09;    big talker 吹牛的人 例句&#xf…

(六)Spring教程——Spring IoC容器(中)

(一)Spring教程——Spring框架简介 (二)Spring教程——Spring框架特点 (三)Spring教程——依赖注入与控制反转 (四)Spring教程——控制反转或依赖注入与Java的反射技术 (五)Spring教程——Spring IoC容器&#xff08;上&#xff09; (六)Spring教程——Spring IoC容器(中) (七)…

Milvus的执行引擎Knowhere

前言 本文将会介绍Knowhere这个概念&#xff0c;它是milvus向量执行引擎的核心。 概览 Knowhere是milvus向量咨询引擎的核心&#xff0c;它将好几个向量相似搜索库聚集在一起&#xff08;包括faiss、hnswlib、annoy&#xff09;。Knowhere也被设计支持异构计算。它控制在什么…

如何使用WindowsSpyBlocker防止Windows系统被恶意监控和跟踪

关于WindowsSpyBlocker WindowsSpyBlocker是一款功能强大的Windows系统安全防护工具&#xff0c;该工具基于Go语言开发&#xff0c;WindowsSpyBlocker以一个单独的可执行程序发布&#xff0c;可以帮助广大用户防止自己的Windows系统被恶意监控和跟踪。 WindowsSpyBlocker能够利…

使用 LlamaParse 进行 PDF 解析并创建知识图谱

此 Python 笔记本提供了有关利用 LlamaParse 从 PDF 文档中提取信息并随后将提取的内容存储到 Neo4j 图形数据库中的综合指南。本教程在设计时考虑到了实用性&#xff0c;适合对文档处理、信息提取和图形数据库技术感兴趣的开发人员、数据科学家和技术爱好者。 该笔记本电脑的主…

人工智能是“数字鹦鹉”还是有了自我意识?

相关说明 这篇文章涉及到的书籍是《解构大语言模型&#xff1a;从线性回归到通用人工智能》&#xff0c;欢迎有兴趣的读者多多支持。 部分章节内容可以参考&#xff1a; 理解大语言模型&#xff08;二&#xff09;——从零开始实现GPT-2利用神经网络学习语言&#xff08;四&…

ICRA 2024: NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院等研究人员开发了精细操作的手术机器人

英伟达&#xff08;NVIDIA&#xff09;正与学术研究人员合作&#xff0c;研究手术机器人。 NVIDIA 联合多伦多大学、加州大学伯克利分校、苏黎世联邦理工学院和佐治亚理工学院的研究人员开发了 ORBIT-Surgical&#xff0c;一个训练机器人的模拟框架&#xff0c;可以提高手术团…

拥抱红利行业,短视频带货助力普通人逆袭

短视频带货&#xff0c;作为当下最热门的副业选择之一&#xff0c;不仅迎合了现代消费者购物习惯的改变&#xff0c;还借助了互联网平台的强大传播力&#xff0c;让每一个普通人都有机会成为带货达人。 首先&#xff0c;短视频带货具有低门槛、易上手的特点。你无需具备专业的…

Docker-数据卷的挂载

文章目录 数据卷概念数据卷实现机制数据卷特性数据卷操作数据卷挂载通用命令匿名挂载具名挂载数据卷继承容器数据卷只读容器数据卷读写-默认 总结 数据卷概念 为了很好的实现数据保存和数据共享&#xff0c;Docker提出了Volume这个概念&#xff0c;简单的说就是绕过默认的联合文…

upload-labs 通关方法

目录 Less-1&#xff08;JS前端验证&#xff09; Less-2&#xff08;MIME验证&#xff09; Less-3&#xff08;黑名单&#xff0c;特殊过滤&#xff09; Less-4&#xff08;黑名单验证&#xff0c;.htaccess&#xff09; Less-5&#xff08;黑名单&#xff0c;点空格点绕过…

「项目」负载均衡在线OJ(ONLINE_JUDGE)系统

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

Unity 开发Hololens,制作面板跟随眼镜一起移动,(面板跟踪)

Hololens滑动框以及面板跟踪 创建空物体&#xff0c;并添加组件 SolverHandler、RedialView、FollowMeToggle 创建按钮&#xff0c;控制停止/开始跟踪 创建一个Hololens自带的按钮放到右上角&#xff0c;并添加事件 创建蓝色背景板 创建空物体Backplate&#xff0c;下面再…

专题汇编 | ChatGPT引领AIGC新浪潮(一)

ChatGPT的产生与迭代 2022年11月末,美国人工智能研究实验室OpenAI推出ChatGPT。上线的ChatGPT只用了2个月,活跃用户数就突破了1亿,创造了应用增速最快的纪录。 ChatGPT是什么 ChatGPT是一种人工智能技术驱动的自然语言处理(Natural Language Processing,NLP)工具,使用的…

【Linux学习】进程基础API

下面是有关进程基础API的相关介绍&#xff0c;希望对你有所帮助&#xff01; 小海编程心语录-CSDN博客 目录 1. 僵尸进程与孤儿进程 1.1 孤儿进程 1.2 僵尸进程 2. 监视子进程 2.1 wait() 2.2 waitpid() 3. 执行新程序 exec族函数 4. 守护进程 1. 僵尸进程与孤儿进程…

PHP报错 Notice: Undefined index: action in

upload靶场PHP报错 Notice: Undefined index: action in 修改 php.ini 中的 error配置下错误显示方式&#xff1a;将error_reporting E_ALL 修改为 error_reporting E_ALL & ~E_NOTICE 修改后重启下APCHE服务即可。

Java方法的基本用法

Java方法的基本用法 前言一、什么是方法方法存在的意义示例 二、方法定义语法基本语法代码示例注意事项 三、方法调用的执行过程基本规则代码示例计算两个整数相加计算 1! 2! 3! 4! 5! 四、实参和形参的关系代码示例交换两个整型变量原因分析解决办法 五、没有返回值的方法…