Original address: http://blogread.cn/it/article/6086?f=wb
Foreword:
First of all, I am not an expert in web security, so this is not an expert-level article on web security. It is a study of notes and a careful summary of the article. There are some things in it that we phpers cannot easily discover or do not pay attention to. So I wrote it down for easy reference later. There must be dedicated web security testers in large companies, and security is not the scope of PHPer's consideration. But as a PHPer, the security knowledge is: "Knowing that there is such a thing, I will naturally pay attention to it when programming". If there is anything wrong or wrong, please contact: chen_bin_wen@163.com/445235728@qq.com
Summary :
1. Some PHP security configurations
(1) Turn off the php error prompt function
(2) Turn off some "bad features"
(3) Strictly configure file permissions.
2. Strict data verification, not all your users are “good” people
2.1 In order to ensure the security and robustness of the program, data verification should include content.
2.2 Programmers tend to miss points or things that need to pay attention to
3. Anti-injection
3.1 Simply determine whether there is an injection vulnerability and the principle
3.2 Common mysql injection statements
(1) No username and password required
(2) Taking advantage of a user without entering the password
(3) Guess a user’s password
(4) Elevate privileges when inserting data
(5) Update privilege escalation is the same as insert privilege escalation
(6) Malicious updates and deletions
(7)union, join, etc.
(8) Wildcard symbols %, _
(9) There are also a lot of guessed table information injected into sql
33 Some methods to prevent injection
2.3.1 Some functions and precautions that PHP can use to prevent injection.
2.3.2 Anti-injection character priority.
2.3.3 Anti-injection code
(1) If the parameter is a number, use the intval() function directly
(2) Filtering of non-text parameters
(3) Text data anti-injection code.
(4) Of course there are other codes combined with addslashes and mysql_escape_string.
4. Prevent xss attacks
4.1Xss attack process
4.2 Common xss attack places
4.3 Anti-XSS methods
5. CSRF
5.1 Brief explanation of CSRF principles
5.2 Prevention methods
6. Anti-hotlinking
7. Prevent CC attacks
-------------------------------------------------- -----------------------
1, phpSome security configurations
(1)Turn off the php error prompt function
Change display_errors in php.ini to
display_errors = OFF
or add
before the php fileerror_reporting(0)
1) Use error_reporting(0); Failure example:
A file code:
error_reporting(0);
echo 555
echo 444;
?>
Error:
Parse error: parse error, expecting `','' or `';'' in E:webphp2.php on line 4
2) Use error_reporting(0); Successful example:
a file code:
error_reporting(0);
include("b.php");
?>
b file code:
echo 555
echo 444;
?>
This is a lot of phpers saying that using error_reporting(0) does not work. In the first example, there is a fatal error in A.php, which prevents execution. If the server cannot be executed, it does not know that it has this function, so the same error is reported.
In the second example, a.php is executed successfully, then the server knows that there is an error suppression function, so even if b.php has an error, it is suppressed.
ps: MySQL error cannot be suppressed.
(2)Turn off some "bad features"
1) Turn off the magic quotes function
Set magic_quotes_gpc = OFF in php.ini
Avoid repeated escaping with addslashes
2) Turn off register_globals = Off
Put register_globals = OFF in php.ini
With register_globals = ON
Address column: http:www.phpben.com?bloger=benwin
//$bloger = $_GET['bloger'] //Because register_globals = ON, this step is not necessary and you can directly use $bloger
echo$bloger;
?>
This situation will cause some uninitialized variables to be easily modified, which may be fatal. So turn register_globals = OFF
(3) Strictly configure file permissions.
Assign permissions to the corresponding folders. For example, files containing uploaded images cannot have execution permissions and can only be read
2, strict data verification, not all your users are “good” people .
I remember when the author and a friend were discussing data verification, he said something: Don’t think so bad of all your users! But the problem I want to say should not appear in our development scenario. What we have to do is to strictly verify and control the data flow. Even if one of the 100 million users is a bad user, it is enough to be fatal. Besides, good users sometimes fail in data input. When he accidentally entered Chinese into the box, he had inadvertently become "bad".
2.1In order to ensure the security and robustness of the program, data verification should include
(1) Whether key data exists. If the deleted data id exists
(2) Whether the data type is correct. For example, whether the deleted data id is an integer
(3) Data length. If the field is of char(10) type, strlen is required to determine the data length
(4) Whether the data contains dangerous characters
Data Verification Some people advocate writing security verification slowly after the functions are completed, and some people write verification while developing. The author prefers the latter. I have tried both, and found that the verification written by the latter is relatively robust. The main reason is that the security issues that are thought of when first developing are relatively complete. There are two problems when writing after the functions are developed. One is PHPer is eager to complete the indicator and completes the task hastily. Secondly, it does miss some points.
2.2Programmers tend to miss points or things that need to pay attention to :
(1) The data entering the database must be securely verified. When the author participated in the development of an internal system in a company in Guangzhou, I saw $_POST data being passed directly to the class function classFunctionName($_POST). The reason turned out to be that the company For internal use, it doesn’t need to be so strict. Putting aside the issue of coupling between logical operations and data manipulation, operations without judgment are fatal. Security verification is a must and there is no reason to shirk it.
(2) Data length problem, such as database table field char(25), most PHPers consider whether it is empty and whether the data type is correct, but ignore the character length. Ignoring it is mostly because they are too lazy to judge the length. . (This occurs more among novices, and the author once had such thoughts)
(3) I think that the front-end has been judged and verified using js, and the back-end does not need to be judged and verified. This is also fatal. You must know that it only takes a few minutes to forge a form. JS judgment is only to reduce the number of user submissions to improve user experience, reduce http requests and reduce server pressure. In a safe situation, you cannot prevent "villain "Of course, if the legitimate user is under the control of js verification, it will be perfect, but as phper we cannot only have js verification and abandon another security verification.
(4) Lack of verification for certain attributes of the form such as select, checkbox, radio, button, etc. The developers have set their values and value ranges (whitelist values) on the web page. These attribute values are in JS verification generally does not verify, because legitimate users only have the right to choose and not modify, and then PHPer will not verify the data when it accepts the data at the backend to process the verification data. This is an inertial thinking, and security issues arise. A fake form is enough for a villain to be fatal.
(5) The name of the corresponding element of the form is consistent with the field name of the data table. For example, the user name field of the user table is user_name, and then the user name input box in the form is also user_name. This is no different from a violent database.
(6) Filtering dangerous characters such as preventing injection will be explained separately below.
3, anti-injection
3.1Simply determine whether there is an injection vulnerability and the principle.
Website: http:www.phpben.com/benwin.php?id=1 runs normally, sql statements such as: select * from phpben where id = 1
(1) Website: http:www.phpben.com/ benwin.php?id=1' SQL statement such as: select * from phpben where id = 1' Then running exception, which can explain benwin The .php file does not perform "'" filtering and intval() integer conversion on the id value. Of course, I would like to know if other characters such as "%", "/*", etc. can be exhaustively tested using similar methods (many tests Software usage)
(2) URL: http:www.phpben.com/ benwin.php?id=1 and 1=1 The sql statement may be select * from phpben where id = 1 and 1=1 , runs normally and the result is the same as http:www.phpben.com/benwin.php?id=1, it means benwin.php may not filter the spaces " ", and "and" (it is possible here, so take a look a little)
(3) URL: http:www.phpben.com/ benwin.php?id=1 and 1=2 The sql statement may be select * from phpben where id = 1 and 1=2 If the running result is abnormal, it means that "and 1=2" in the sql statement works, so if all three conditions are met, it is certain that benwin.php has an injection vulnerability.
ps: Use the get method to verify here, and post can also be used. Just enter the value as above and you can verify it one by one.
This means
3.2Common mysql injection statements.
(1) No username and password required
//Normal statement
$sql ="select * from phpben where user_name='admin' and pwd ='123'";
//Enter ‘or’=’or’ or ’or 1=’1 in the user name box and then the sql is as follows
$sql ="select * from phpben where user_name=' 'or'='or'' and pwd ='' ";
$sql ="select * from phpben where user_name=' 'or 1='1' and pwd ='' ";
This way you don’t have to enter a password. By the way, when I see the login box, I have the urge to try it.
(2) Take advantage of a user without entering a password.
//Normal statement
$sql ="select * from phpben where user_name='$username' and pwd ='$pwd'";
//The user name used is benwin, then enter benwin’# in the user name box. You can have or without a password, then $sql becomes
$sql ="select * from phpben where user_name=' benwin'#' and pwd ='$pwd'";
This is because one of the annotations in mysql is "#". The # in the above statement has annotated the following content, so the password can be left blank or entered arbitrarily. Some people on the Internet said that "/*" is used to annotate. What the author wants to mention is that when the annotation is only started and not ended with "*/", mysql will report an error, and it does not say "/**/" cannot be noted, but it is difficult to add "*/" To end the note, there is also "--" that can also be noted in mysql, but please note that there is at least one space after "--", which is "--". Of course, the anti-injection code must take all three into account, It is worth mentioning that many anti-injection codes do not take "--" into the anti-injection scope.
(3) Guess a user’s password
//Normal statement
$sql ="select * from phpben.com where user_name='$username' and pwd ='$pwd'";
//Enter “benwin’ and left(pwd,1)=’p’#” in the password input box, then $sql is
$sql ="select * from phpben.com where user_name=' benwin' and left(pwd,1)='p'#' and pwd ='$pwd'";
If it runs normally, the first character of the password is p, and guess the remaining characters in the same way.
(4) Elevate privileges when inserting data
//Normal statement, level 1
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values('benwin','iampwd',1) ";
//Change the password string to change the statement into
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values('benwin','iampwd',5)#',1) ";
$sql = "insert into phpben.com (`user_name`,`pwd`,`level`) values('benwin','iampwd',5)-- ',1) ";This puts a permission Elevate user rights to level 1
(5) The same goes for update privilege escalation and insert privilege escalation
//Normal statement
$sql = "update phpben set `user_name` ='benwin', level=1";
//The final $sql obtained by entering the username value
$sql = "update phpben set `user_name` ='benwin',level=5#', level=1";
$sql = "update phpben set `user_name` ='benwin',level=5-- ', level=1";
(6) Malicious updates and deletions
//Normal statement
$sql = "update phpben set `user_name` = 'benwin' where id =1";
//After injection, the malicious code is "1 or id>0"
$sql = "update phpben set `user_name` = 'benwin' where id =1 or id>0";
//Normal statement
$sql = "update phpben set `user_name` =’benwin’ where id=1";
//After injection
$sql = "update phpben set `user_name` ='benwin' where id>0#' where id=1";
$sql = "update phpben set `user_name` ='benwin' where id>0-- ' where id=1";
(7)union, join, etc.
//Normal statement
$sql ="select * from phpben1 where `user_name`=’benwin’ ";
//After injection
$sql ="select * from phpben1 where`user_name`=’benwin’ uninon select * from phpben2#’ ";
$sql ="select * from phpben1 where`user_name`=’benwin’ left join……#’ ";
(8) wildcard symbols %, _
//Normal statement
$sql ="select * from phpben where `user_name`=’benwin’ ";
//Inject wildcard symbol % to match multiple characters, and a _ matches one character, such as __, matches two characters
$sql ="select * from phpben where `user_name` like ’%b’ ";
$sql ="select * from phpben where `user_name` like ’_b_’ ";
In this way, as long as there is a user whose name starts with b, it will run normally. "_b_" matches three characters, and the middle one of these three characters is b. This is why when introducing the addslashes() function, you are prompted to note that % and _ are not escaped (actually, this is because many phpers don’t know why to filter % and _ underscores, and just blindly follow the online code)
(9) There are also a lot of guessed table information injected into sql
//Normal statement
$sql ="select * from phpben1 where`user_name`='benwin'";
//Guess the table name. If it runs normally, it means there is a phpben2 table
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(*) from phpben2 )>0#' ";
//Guess the table fields. If the operation is normal, it means that there is field colum1 in the phpben2 table
$sql ="select * from phpben1 where`user_name`='benwin' and (select count(colum1) from phpben2 )>0#'";
//Guess field value
$sql ="select * from phpben1 where`user_name`='benwin' and left(pwd,1)='p'#''";
Of course there are many more, and the author has not studied to the level of a professional. Here are some common ones, and they are what PHPer should know and master, instead of blindly copying and pasting some anti-injection codes online. However, I don't understand why.
The following anti-injection methods may be easier to understand in retrospect.
3.3Some methods to prevent injection
3.3.1 phpSome functions and precautions that can be used to prevent injection.
(1) addslashes and stripslashes .
Addslashes add slashes "'", """, "\", "NULL" to these "'", """, "", "NULL". Stripslashes does the opposite. What should be noted here is php. Is magic_quotes_gpc=ON enabled in ini? Duplication will occur if addslashes is enabled. So when using it, you must first check with get_magic_quotes_gpc()
The general code is similar:
if(!get_magic_quotes_gpc())
{
$abc = addslashes($abc);
}
In fact, everyone who has learned PHP a little bit knows this, but the author wants to introduce it systematically (I said it is not an expert-level article), so I also wrote it down. addslashes
(2)mysql_escape_string() and mysql_ real _escape_string()
mysql_real_escape_string can only be used under (PHP 4 >= 4.3.0, PHP 5). Otherwise, you can only use mysql_escape_string
if (PHP_VERSION >= '4.3')
{
$string = mysql_real_escape_string($string);
}else
{
$string = mysql_escape_string($string);
}
The difference between mysql_escape_string() and mysql_ real _escape_string() is that the latter will determine the current database connection character set. In other words, a similar error will occur without connecting to the database:
Warning: mysql_real_escape_string() [function.mysql-real-escape-string]: Access denied for user 'ODBC'@'localhost' (using password: NO) in E:webphptest.php on line 11
(3) Character replacement function and matching function
The str_replace() and perg_replace() functions are also mentioned here because these functions can be used to filter or replace some sensitive and fatal characters.
3.3.2Anti-injection character priority.
To prevent injection, you must first know what injection characters or keywords there are. Common mysql injection characters include character delimiters such as "'" and """; logical keywords such as "and" and "or"; mysql notes Characters such as "#", "--", "/**/"; mysql wildcard characters "%", "_"; mysql keyword "select|insert|update|delete|*|union|join|into|load_file| outfile”
(1)For some parameters with prescribed formats, the highest priority for anti-injection is "space".
For example, some parameters such as bank card number, ID number, email address, phone number, date of birth, postal code, etc. have their own format and the format stipulates that there cannot be spaces. When filtering, spaces are generally filtered out first ( Including some "variants" of spaces), because other characters define symbols, logical keywords, and mysql notes. Note that the following figure shows that the important ones are "'", " "
ps: Variants of space characters are: "%20", "n", "r", "rn", "nr", "chr("32")" This is why mysql_escape_string () and mysql_real_escape_string() two functions escape "n" and "r". In fact, many PHPers only know how to escape n and r without knowing the reason. When MySQL parses n and r, they treat them as spaces. The author has tested and verified it, so I will not post the code here.
(2)“and”, “or”, “”, “#”, “--”
Logical key can combine many injected codes; mysql annotation annotates all the characters behind the inherent sql code so that the injected sql statement can run normally; "" can also be combined with many Inject characters x00,x1a.
ps: SQL parsing "#" and "--" are not considered by most mysql anti-injection codes, and are also ignored by many phpers. Also, because some PHPers use "-" to separate parameters when assigning values, the author recommends not to write parameters like this. Of course, you can also use "--" when filtering parameters (note that there are spaces. If there are no spaces, it will not be parsed as Note) When filtering as a whole instead of filtering "-", this avoids excessive filtering parameters.
(3)“null”, “%”, “_”
These cannot be independent and should not be used under specific circumstances. For example, the wildcard characters "%, _" must be included in the mysql like clause. Therefore, the filtering of "%" and "_" is generally filtered only when the search is related. They cannot be included in the normal filtering queue, because some such as mailboxes can have the "_" character
(4) Keyword "select|insert|update|delete|*|union|join|into|load_file|outfile"
Maybe you will ask why these important keywords have such low priority. What the author wants to say is because these keywords are not harmful when purchased without "'", """, "", "and", "or", etc. In other words, these keywords are not "independent", "Dependency " is particularly large. Of course, the low priority does not mean that filtering is not necessary.
3.3.3Anti-injection code.
(1)If the parameter is a number, use the intval() function directly
Note: Many popular anti-injection codes on the Internet are just filtered by addslashes(), mysql_escape_string(), mysql_real_escape_string() or any combination of the three, but phper thought it was filtered and accidentally There is also a loophole, that is when the parameter is a number:
$id = addslashes($_POST['id']); //The correct one is $id = intval($_POST['id']);
$sql =" select * from phpben.com where id =$id";
$sql =" select * from phpben.com where id =1 or 1=1";
It is easy to find that after the post data is filtered by addslashes, many injections have no effect, but $id does not have an intval, leading to the existence of vulnerabilities. This is a small detail. If you are not careful, it will cause loopholes.
(2)Filtering of non-text parameters
Text parameters refer to titles, messages, content, etc. that may contain “’”, “’”, etc. It is impossible to escape or replace them all during filtering.
But non-text data is OK.
function _str_replace($str )
{
$str = str_replace(" ","",$str);
$str = str_replace("n","",$str);
$str = str_replace("r","",$str);
$str = str_replace("'","",$str);
$str = str_replace('"',"",$str);
$str = str_replace("or","",$str);
$str = str_replace("and","",$str);
$str = str_replace("#","",$str);
$str = str_replace("\","",$str);
$str = str_replace("-- ","",$str);
$str = str_replace("null","",$str);
$str = str_replace("%","",$str);
//$str = str_replace("_","",$str);
$str = str_replace(">","",$str);
$str = str_replace("<","",$str);
$str = str_replace("=","",$str);
$str = str_replace("char","",$str);
$str = str_replace("declare","",$str);
$str = str_replace("select","",$str);
$str = str_replace("create","",$str);
$str = str_replace("delete","",$str);
$str = str_replace("insert","",$str);
$str = str_replace("execute","",$str);
$str = str_replace("update","",$str);
$str = str_replace("count","",$str);
return$str;
}
ps:
There are also some general hrefs operated from the list page, which are "phpben.php?action=delete&id=1". Please pay attention at this time. _str_replace($_GET['action']) will filter out the parameters. The author Generally, sensitive keys are not used as parameters. For example, delete will be written as del, and update will be written as edite, as long as it does not affect readability;
Also, the author noted that the above code filtering underscores was omitted because some parameters can use underscores, so you can decide how to filter by yourself;
Some codes use keywords as key filter objects. In fact, str_replace of keywords is easy to "pass". The characters filtered by str_replace ("ininsertsert") are still inserts, so the key is other characters rather than mysql keywords.
(3)Text data anti-injection code.
Text parameters refer to data such as title, message, content, etc. It is impossible to filter out using str_replace(), which will lead to data integrity, which is very undesirable.
Code:
function no_inject($str)
{
if(is_array($str))
{
foreach($stras$key =>$val)
}else
{
//Replace the first letter of some sensitive keywords, such as or, use "or" instead
$str = str_replace(" "," ",$str);
$str = str_replace("\","\",$str);
$str = str_replace("'"," ' ",$str);
$str = str_replace('"'," " ",$str);
$str = str_replace("or"," o r",$str);
$str = str_replace("and"," and",$str);
$str = str_replace("#","# ",$str);
$str = str_replace("-- ","-- ",$str);
$str = str_replace("null","null",$str);
$str = str_replace("%","%",$str);
//$str = str_replace("_","_",$str);
$str = str_replace(">","",$str);
$str = str_replace("<",">",$str);
$str = str_replace("=","=",$str);
$str = str_replace("char","char",$str);
$str = str_replace("declare","declare",$str);
$str = str_replace("select","select",$str);
$str = str_replace("create","reate",$str);
$str = str_replace("delete","delete",$str);
$str = str_replace("insert","insert",$str);
$str = str_replace("execute","execute",$str);
$str = str_replace("update","update",$str);
$str = str_replace("count","count",$str);
} }
return$str;
}
(4)Of course there are other codes combined with addslashes, mysql_escape_string.
The anti-injection codes actually come and go in those combinations, and then they are adapted according to their own program codes. The author has not considered all of these codes. It is better that cookes, sessions, and requests are not fully filtered. The important thing is to know the principle, why these characters are filtered, and what harm the characters have. Of course, there are some aspects that the author has not considered nor is able to consider, such as what other keywords are there. Welcome to mailto: chen_bin_wen@163.com/445235728@qq.com
4, prevent xss attack
XSS: cross site script, why is it not called css, so as not to be confused with div+css.
4.1Xss attack process:
(1) Found that site A has an xss vulnerability.
(2)Inject xss vulnerability code. It can be js code, Trojan horse, script file, etc. Here, if the benwin.php file of station A has a vulnerability.
(3)Use some methods to deceive relevant personnel of station A to run benwin.php, and use some member information of relevant personnel such as cookies, permissions, etc.
Related personnel:
Administrators (such as Tieba moderators) generally have certain permissions. The purpose is to borrow the administrator's authority or perform privilege escalation, add or add administrators, add backdoors, upload Trojans, or further penetrate and other related operations.
Members of Station A: Members run benwin.php of Station A. The purpose is generally to steal members’ information on site A.
Method:
1) Send information, such as website address, to lure relevant people to benwin.php on site A. This is local deception
2) Send deceptive information or emails on other websites.
Usually using disguised URLs to trick relevant personnel of station A into clicking into benwin.php
(4)The third step is usually an xss attack. If you want to attack further, repeat steps (2) and (3) to achieve the goal.
A simple example of xss attack
Code:
benwin.php file
<html>
<head>
<title>Simple xss attack exampletitle>head>
<metahttp-equiv="Content-Type"content="text/html; charset=utf-8">
<dody>
<formaction="phpben.com?user_name=">
<inputtype="submit"value="submit">
form>
body>
html>
When the value of username $user_name is "benwin" onSubmit="alert('This is an example of xss attack');" class= ""(here)
<formaction="phpben.com?user_name=benwin"onSubmit="alert('This is an example of an xss attack');"class= "">
<inputtype="submit"value="submit">
form>
A prompt box will pop up when submitting the form.
(1) It is obvious that $user_name did not filter xss characters when saving it into the database (similar to anti-injection, here is an example) ==> Vulnerability found
(2) Construct xss code: benwin" onSubmit="alert('This is an example of xss attack');" class="" Pass in the database
(3) Deceive relevant personnel to come in and click the "Submit" button
4.2Common xssAttack places
(1)Js place
$testname的值只要符合js闭合关系:“";alert("test xss ");”(以下同理)
(2)form表单里面
<inputtype="text"name="##"value=""/>
(3)a标签
<ahref="benwin.php?id= ">a标签可以隐藏xss攻击a>
(4)用得很多的img标签
<imgsrc=""/>
甚至一些文本中插入整个img标签并且用width、 height、css等隐藏的很隐蔽
(5)地址栏目
总之,有输出数据的地方,更准确的说是有输出用户提交的数据的地方,都有可能是XSS攻击的地方。
4.3防XSS方法
防xss方法其实和防注入很相似,都是一些过滤、代替、实体化等方法
(1)过滤或移除特殊的Html标签。
例如:< 、>、<,、> ’、”、