网络安全-php安全知识点

写给和我一样没学过php的安全小白,只是为了让你看懂php代码,专门学后端的请出门左转。学安全需要学的东西太多,你不可能把js学的和做前端的同学一样好、把php学的和做后端的一样好,把数据库学的和做数据库优化的同学一样好,把Apache学的和做服务器端的同学一样好,我们只能关注他们涉及的领域中不安全的因素,找到漏洞,提出修改意见。

php是后端常用的语言,在靶机或CTF比赛中也需要进行php代码审计,所以就看看从学安全的角度需要关心哪些部分。

语法与注释

PHP以 <?php 开始,以 ?> 结束:

<?php

// PHP 代码

?>

<?php

// 这是 PHP 单行注释

/*

这是

PHP 多行

注释

*/

?>

输出

在 PHP 中有两个基本的输出方式: echo 和 print。

echo 和 print 区别:

  • echo - 可以输出一个或多个字符串。
  • print - 只允许输出一个字符串,返回值总为 1。

echo是经常用的,一般用于回显,比如sql注入时回显查询语句结果。

变量

PHP 变量规则:

  • 变量以 $ 符号开始,后面跟着变量的名称
  • 变量名必须以字母或者下划线字符开始
  • 变量名只能包含字母数字字符以及下划线(A-z、0-9 和 _ )
  • 变量名不能包含空格
  • 变量名是区分大小写的

php是弱类型语言,不用在变量前面加类型。从学安全的角度,能看懂哪个是变量就ok了,如果以后学的更深入了,需要使用php来写POC,进行持续性漏洞再回过头来学习命名规则等。

弱类型安全

php中有一些相等的值

  • ''==0==false==NULL
  • '123'==123
  • 'abc'==0
  • '123a'==123
  • '0x01'==1
  • '0e123456789'=='0e987654321'
  • false\] ==\[0\]==\[NULL\]==\[''

  • true == 1

在PHP中,比较两个值是否相等可以使用"=="或"===",前者会自动进行类型转换。

复制代码
<?php
$input = "1abc";
if($input==1)
{
	echo "flag";
}
?>

结果如下:

其他的请读者自行尝试。

超级全局常量

常量值被定义后,在脚本的其他任何地方都不能被改变。

PHP 超级全局变量列表:

  • $GLOBALS

$GLOBALS 是一个包含了全部变量的全局组合数组,变量的名字就是数组的键,在一个PHP脚本的全部作用域中都可以访问。

$GLOBALS["___mysqli_ston"]

  • $_SERVER

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。

元素/代码 描述
$_SERVER['PHP_SELF'] 当前执行脚本的文件名,与 document root 有关。例如,在地址为 http://example.com/test.php/foo.bar 的脚本中使用 $_SERVER['PHP_SELF'] 将得到 /test.php/foo.bar。FILE 常量包含当前(例如包含)文件的完整路径和文件名。 从 PHP 4.3.0 版本开始,如果 PHP 以命令行模式运行,这个变量将包含脚本名。之前的版本该变量不可用。
$_SERVER['GATEWAY_INTERFACE'] 服务器使用的 CGI 规范的版本;例如,"CGI/1.1"。
$_SERVER['SERVER_ADDR'] 当前运行脚本所在的服务器的 IP 地址。
$_SERVER['SERVER_NAME'] 当前运行脚本所在的服务器的主机名。如果脚本运行于虚拟主机中,该名称是由那个虚拟主机所设置的值决定。
$_SERVER['SERVER_SOFTWARE'] 服务器标识字符串,在响应请求时的头信息中给出。 (如:Apache/2.2.24)
$_SERVER['SERVER_PROTOCOL'] 请求页面时通信协议的名称和版本。例如,"HTTP/1.0"。
$_SERVER['REQUEST_METHOD'] 访问页面使用的请求方法;例如,"GET", "HEAD","POST","PUT"。
$_SERVER['REQUEST_TIME'] 请求开始时的时间戳。从 PHP 5.1.0 起可用。 (如:1377687496)
$_SERVER['QUERY_STRING'] query string(查询字符串),如果有的话,通过它进行页面访问。
$_SERVER['HTTP_ACCEPT'] 当前请求头中 Accept: 项的内容,如果存在的话。
$_SERVER['HTTP_ACCEPT_CHARSET'] 当前请求头中 Accept-Charset: 项的内容,如果存在的话。例如:"iso-8859-1,*,utf-8"。
$_SERVER['HTTP_HOST'] 当前请求头中 Host: 项的内容,如果存在的话。
$_SERVER['HTTP_REFERER'] 引导用户代理到当前页的前一页的地址(如果存在)。由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改 HTTP_REFERER 的功能。简言之,该值并不可信。)
$_SERVER['HTTPS'] 如果脚本是通过 HTTPS 协议被访问,则被设为一个非空的值。
$_SERVER['REMOTE_ADDR'] 浏览当前页面的用户的 IP 地址。
$_SERVER['REMOTE_HOST'] 浏览当前页面的用户的主机名。DNS 反向解析不依赖于用户的 REMOTE_ADDR。
$_SERVER['REMOTE_PORT'] 用户机器上连接到 Web 服务器所使用的端口号。
$_SERVER['SCRIPT_FILENAME'] 当前执行脚本的绝对路径。
$_SERVER['SERVER_ADMIN'] 该值指明了 Apache 服务器配置文件中的 SERVER_ADMIN 参数。如果脚本运行在一个虚拟主机上,则该值是那个虚拟主机的值。
$_SERVER['SERVER_PORT'] Web 服务器使用的端口。默认值为 "80"。如果使用 SSL 安全连接,则这个值为用户设置的 HTTP 端口。
$_SERVER['SERVER_SIGNATURE'] 包含了服务器版本和虚拟主机名的字符串。
$_SERVER['PATH_TRANSLATED'] 当前脚本所在文件系统(非文档根目录)的基本路径。这是在服务器进行虚拟到真实路径的映像后的结果。
$_SERVER['SCRIPT_NAME'] 包含当前脚本的路径。这在页面需要指向自己时非常有用。FILE 常量包含当前脚本(例如包含文件)的完整路径和文件名。
$_SERVER['SCRIPT_URI'] URI 用来指定要访问的页面。例如 "/index.html"。
  • $_REQUEST

用于收集HTML表单提交的数据。

  • $_GET

HTML form标签的属性method="get"时,$_GET可以收集URL中发送的数据。

  • $_POST

HTML form标签的属性method="post"时,$_POST可以收集表单中发送的数据。

  • $_FILES
  • $_ENV
  • $_COOKIE
  • $_SESSION

函数

常用

  • array()

创建数组

  • bool is_numeric ( mixed $var )

检测变量是否为数字或数字字符串,注意,可以是16进制,字符串转16进制可以绕过。is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值。

由于php是弱类型语言,会使用这个函数来判断一下。

  • rand(min,max)

生成随机整数

  • sleep(seconds)

延迟执行当前脚本若干秒

  • bool isset ( mixed var \[, mixed ... ] )

检测变量是否已设置并且非 NULL

  • die(message)

输出一条消息,并退出当前脚本。

  • md5()

以下值在md5加密后以0E开头:

  1. QNKCDZO
  2. 240610708
  3. s878926199a
  4. s155964671a
  5. s214587387a

可以用于md5相等,但两值不相等的情况

base64_encode()、base64_decode()、sha1()strcmp()

传入数组,返回NULL

字符串相关

正则表达式

  • int preg_match ( string pattern , string subject)

执行一个正则表达式匹配

匹配

这里需要注意一下 i ,表示大小写不敏感,即php、PHP、PhP都会被过滤掉,有的时候没有写i,黑名单里面有select关键字时,我们可以使用SELECT来绕过。

  • mb_substr ( string str , int start [, int length = NULL \[, string encoding = mb_internal_encoding() ]] ) : string

返回字符串的一部分,字符串可以包含中文,substr函数是不能包含中文的。

子串

子字符串位置

  • mb_strpos ( string $haystack , string $needle [, int $offset = 0 [, string $encoding = mb_internal_encoding() ]] ) : int

查找字符串在另一个字符串中首次出现的位置(汉字占一个位置),如果没有找到字符串则返回 false。类似的还有:

  • strpos()-查找字符串在另一字符串中最后一次出现的位置(汉字占两个位置)
  • strrpos()-查找字符串在另一字符串中最后一次出现的位置(区分大小写)
  • stripos()-查找字符串在另一字符串中第一次出现的位置(不区分大小写)
  • strripos()-查找字符串在另一字符串中最后一次出现的位置(不区分大小写)

安全问题

由于返回的是false,一旦使用==进行判断,我们可以构造第二个字符串是第一个的开始,即可绕过

复制代码
<?php
$str1 = "abcd";
$str2 = "ab";
if(strpos($str1,$str2)==false)
{
	echo "flag";
}
?>

绕过结果

  • str_replace(find,replace,string,count)

替换字符串中的一些字符(区分大小写),注意,可以通过双写或者大小写进行绕过。

  • mixed preg_filter ( mixed pattern , mixed replacement , mixed subject \[, int limit = -1 [, int &$count ]] )

执行一个正则表达式搜索和替换。这个就不太好弄了,可能需要编码绕过。

  • htmlspecialchars(string,flags,character-set,double_encode)

把一些预定义的字符转换为 HTML 实体。

预定义的字符是:

  1. & (和号)成为 &amp;
  2. " (双引号)成为 &quot;
  3. ' (单引号)成为 '
  4. < (小于)成为 &lt;
  5. > (大于)成为 &gt;

故可以使用单引号的payload进行绕过。

  • strip_tags(string,allow)

剥去字符串中的 HTML、XML 以及 PHP 的标签。

  • addslashes(string)

返回在预定义的字符前添加反斜杠的字符串。

预定义字符是:

  1. 单引号(')
  2. 双引号(")
  3. 反斜杠(\)
  4. NULL

数据库相关

mysqli

  • mysqli_connect(host,username,password,dbname,port,socket)

打开一个到 MySQL 服务器的新的连接。

  • mysqli_error(connection)

返回最近调用函数的最后一个错误描述。

  • mysqli_close(connection)

关闭先前打开的数据库连接。

  • mysqli_query(connection,query,resultmode)

执行某个针对数据库的查询

  • mysqli_fetch_assoc(result)

从结果集中取得一行作为关联数组

  • mysqli_fetch_row(result)

从结果集中取得一行,并作为枚举数组返回

  • mysqli_num_rows(result)

返回结果集中行的数量

  • mysqli_real_escape_string(connection,escapestring)

转义在 SQL 语句中使用的字符串中的特殊字符,难道转义后我们就没有办法注入了?NO!!!

php官方函数参考手册中写到,会被进行转义的字符包括: NUL (ASCII 0),\n,\r,\,'," 和 Control-Z.

也就是或如果是数字型注入,例如,payload是 1 and 1=1# ,那么这个函数没有用,因为payload中不包含以上字符。

另外,在调用 mysqli_real_escape_string() 函数之前, 必须先通过调用mysqli_set_charset()函数或者在 MySQL 服务器端设置字符集。如果字符集设置不当,可以通过宽字节注入来进行绕过。

pdo

PHP 数据对象 (PDO) 扩展为PHP访问数据库定义了一个轻量级的一致接口。

PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据。

  • public PDOStatement PDO::prepare ( string statement \[, array driver_options = array() ] )

为 PDOStatement::execute() 方法准备要执行的SQL语句,SQL语句可以包含零个或多个命名(:name)或问号(?)参数标记,参数在SQL执行时会被替换。这样就没法破坏sql语句的结构,不是拼接。

举例:

prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );

你以为sql语句是

SELECT first_name, last_name FROM users WHERE user_id = id LIMIT 1;

于是使用 1 or 1=1#作为payload,认为下面的sql语句会被执行

SELECT first_name, last_name FROM users WHERE user_id = 1 or 1=1#

但实际上执行的是

SELECT first_name, last_name FROM users WHERE user_id = 1 or 1=1# LIMIT 1;

或者说 直接判断 1 or 1=1# 是不是数字型参数,不是的话根本就不会去执行,也就安全了。

  • bool PDOStatement::bindParam ( mixed parameter , mixed \&variable [, int data_type = PDO::PARAM_STR \[, int length [, mixed $driver_options ]]] )

绑定一个PHP变量到用作预处理的SQL语句中的对应命名占位符或问号占位符。

例如(绑定变量id与prepare里的id):

bindParam( ':id', $id, PDO::PARAM_INT )

  • bool PDOStatement::execute ([ array $input_parameters ] )

执行预处理过的语句。

复制代码
  mixed PDOStatement::fetch ([ int $fetch_style [, int $cursor_orientation = PDO::FETCH_ORI_NEXT [, int $cursor_offset = 0 ]]] )

从一个 PDOStatement 对象相关的结果集中获取下一行。

复制代码
  int PDOStatement::rowCount ( void )

返回上一个由对应的 PDOStatement 对象执行DELETE、 INSERT、或 UPDATE 语句受影响的行数。

伪协议相关

伪协议方法

反序列化漏洞

PHP提供serialize和unserialize函数,将任意类型的数据转换成string类型或者相反。当unserialize函数的参数被用户控制的时候就会形成反序列化漏洞。

serialize函数

serialize() 函数用于序列化对象或数组,并返回一个字符串**,**序列化对象后,可以很方便的将它传递给其他需要它的地方,且其类型和结构不会改变。

string serialize ( mixed $value )

参数

$value: 要序列化的对象或数组。

返回

字符串

unserialize函数

unserialize() 函数用于将通过serialize() 函数序列化后的对象或数组进行反序列化,并返回原始的对象结构。

mixed unserialize ( string $str )

参数

$str: 序列化后的字符串。

返回

返回的是转换之后的值,可为 integer、float、string、array 或 object。

如果传递的字符串不可解序列化,则返回 FALSE,并产生一个 E_NOTICE。

魔法函数

序列化对象就要谈到类,其中有三个魔法函数:__construct、__destruct、__toString。

复制代码
<?php 
class test{
	var $url;
	var $name;
function __construct( $par1, $par2 ) {
   $this->url = $par1;
   $this->name = $par2;
	echo "call __construct<br>";
}
	function __toString() {
		echo "call __toString<br>";
		return $this->url;
	
}
	function __destruct() {
		echo "call __destruct<br>";
		echo "bye<br>";
}
}

$t = new test('https://blog.csdn.net/lady_killer9','FrankYu');
echo $t . PHP_EOL;
?> 

魔法函数

  • __construct在创建对象时被调用
  • __toString在对象被当做字符串时被调用
  • __destruct在脚本结束时被调用

举例

有这样一段代码

复制代码
<?php 
class test{
	var $path = "";
	function __toString() {
		$file = fopen($this->path, "r") or exit("无法打开文件!");
		// 读取文件每一行,直到文件结尾
		while(!feof($file))
		{
    		echo fgets($file). "<br>";
		}
		fclose($file);
		return $this->path;
}
}
$para = '';
echo unserialize($para);
?> 

其中,para是你可控的,代码的作用就是反序列化你传入的参数,然后打印出来。

分析:打印必调用__toString函数,__toString函数中会打开$path文件,所以,我们需要构造一个path为敏感文件路径的test类对象,并得到序列化后的字符串,将该字符串作为参数para。

复制代码
<?php 
class test{
	var $path = "";
	function __toString() {
		$file = fopen($this->path, "r") or exit("无法打开文件!");
		// 读取文件每一行,直到文件结尾
		while(!feof($file))
		{
    		echo fgets($file). "<br>";
		}
		fclose($file);
		return $this->path;
}
}
$hack = new test();
$hack->path = "/box/script.php";
echo serialize($hack);
?> 

得到序列化字符串

成功读取了敏感文件/box/script.php

显示了服务器保存的代码

网络安全学习路线

对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。

同时每个成长路线对应的板块都有配套的视频提供:

需要网络安全学习路线和视频教程的可以在评论区留言哦~

最后
  • 如果你确实想自学的话,我可以把我自己整理收藏的这些教程分享给你,里面不仅有web安全,还有渗透测试等等内容,包含电子书、面试题、pdf文档、视频以及相关的课件笔记,我都已经学过了,都可以免费分享给大家!
    给小伙伴们的意见是想清楚,自学网络安全没有捷径,相比而言系统的网络安全是最节省成本的方式,因为能够帮你节省大量的时间和精力成本。坚持住,既然已经走到这条路上,虽然前途看似困难重重,只要咬牙坚持,最终会收到你想要的效果。

黑客工具&SRC技术文档&PDF书籍&web安全等(可分享)

结语

网络安全产业就像一个江湖,各色人等聚集。相对于欧美国家基础扎实(懂加密、会防护、能挖洞、擅工程)的众多名门正派,我国的人才更多的属于旁门左道(很多白帽子可能会不服气),因此在未来的人才培养和建设上,需要调整结构,鼓励更多的人去做"正向"的、结合"业务"与"数据"、"自动化"的"体系、建设",才能解人才之渴,真正的为社会全面互联网化提供安全保障。

特别声明:

此教程为纯技术分享!本教程的目的决不是为那些怀有不良动机的人提供及技术支持!也不承担因为技术被滥用所产生的连带责任!本教程的目的在于最大限度地唤醒大家对网络安全的重视,并采取相应的安全措施,从而减少由网络安全而带来的经济损失

相关推荐
CYRUS STUDIO37 分钟前
FART 脱壳某大厂 App + CodeItem 修复 dex + 反编译还原源码
android·安全·逆向·app加固·fart·脱壳
枷锁—sha43 分钟前
护网行动面试试题(2)
web安全·面试·职场和发展
hanniuniu131 小时前
网络安全厂商F5推出AI Gateway,化解大模型应用风险
人工智能·web安全·gateway
SilentCodeY2 小时前
Ubuntu 系统通过防火墙管控 Docker 容器
linux·安全·ubuntu·系统防火墙
我是老孙3 小时前
windows10 php报错
开发语言·php
海天胜景4 小时前
Delphi SetFileSecurity 设置安全描述符
安全
阿部多瑞 ABU4 小时前
# 从底层架构到应用实践:为何部分大模型在越狱攻击下失守?
gpt·安全·ai·自然语言处理
KKKlucifer4 小时前
从边界防护到内生安全:企业网络安全进化路线图
安全·web安全
Kjjia4 小时前
将内容明文存储在indexDB后,被指着鼻子骂道赶紧把数据隐藏...
前端·安全
WhoisXMLAPI5 小时前
利用 DNS 情报缓解报税季的网络威胁
运维·网络·安全·web安全