问题
I am currently being attacked with a URL of the form:
/act/test.php?CourseId=66'+and(%2f**%2fsElEcT+1+%2f**%2ffRoM(%2f**%2fsElEcT+count(*),%2f**%2fcOnCaT((%2f**%2fsElEcT(%2f**%2fsElEcT(%2f**%2fsElEcT+%2f**%2fcOnCaT(0x217e21,ifnull(MailingDate,char(32)),0x217e21)+%2f**%2ffRoM+contin5_Mailing.Customers+%2f**%2flImIt+1400,1))+%2f**%2ffRoM+information_schema.%2f**%2ftAbLeS+%2f**%2flImIt+0,1),floor(rand(0)*2))x+%2f**%2ffRoM+information_schema.%2f**%2ftAbLeS+%2f**%2fgRoUp%2f**%2fbY+x)a)+and+'1'='1
and
/act/index.php?Ad=999999.9+%2f**%2fuNiOn%2f**%2faLl+%2f**%2fsElEcT+0x393133353134353632312e39
I wish to block these types of attacks with a reasonably straightforward validation of the url early in the PHP processing of my website.
Since a signature of this type of attack seems to be "%2f*" (meaning "/*" which is injecting a comment, I guess), I used this hamfisted approach which does work for this specific attack:
$UrlParms = $_SERVER['REQUEST_URI'];
$FoundAnomalies = (strpos($UrlParms, '%2f*')); //* If we found anomalies in the parameters
if ($FoundAnomalies)
{
LogErrorToFileOnly("BOGUS URL: ".$FoundAnomalies." ".$UrlParms);
die();
}
which logs the error to a file and dies before actually outputting any HTML. This has significantly reduced the cpu and memory load on my server by failing early and not later after actually opening a database and executing this failed SQL injection.
I know this is kind of a "whack-a-mole" approach, but can you tell me if this seems reasonable and whether there are any other strings to look for that indicate a SQL injection attack? Or point me to any general purpose php code that would handle this better? Note that I am only interested in code that would look at the URL and parameters very early on in the PHP execution and knows nothing about what parameters are legal for use later in the code.
Historic note: I wrote this e-commerce code 15 years ago using PHP and MySQL and it continues to function to this day. However, the standards of the time didn't really consider this type of security, and I don't know if SQL injection even existed at the time. The effort it would take to rewrite the entire website is not really worth it, so please don't admonish me to scrub every individual parameter, etc., etc. I would write it differently today, but I just want to try to detect SQL injection with simple URL filtering first thing in the php processing then abort.
Final edit 5/11/2018:
Despite the naysayers, I have created some PHP code and Javascript that solves this problem (and many related problems) nicely, and has been thwarting the active hackers attacking my commercial website. It has been working for two months now. The code is posted below in my answer.
回答1:
There are Web App Firewall products that use URL whitelisting as an attempt to filter out any unauthorized types of URLs.
- GreenSQL
- Oracle Database Firewall
- Apache mod_security
Generally you need to "teach" these firewalls what types of URLs are legitimate, and then the firewall rejects any request that isn't in the list of whitelisted URLs.
But in my opinion, fixing your code to use SQL query parameters is less work than integrating a WAF product into your site.
If you want to avoid rewriting lots of code all at once, and you prefer a "whack-a-mole" approach, I encourage you to fix the code in one of your PHP pages at a time, as you detect attempted SQL injection attacks. Start with index.php
of course. If attackers sees that the homepage is resistant to SQL injection, most might assume the rest of your pages are secure too, and move on to other sites. But you never know, they might just test all of your pages. If you were a hacker, wouldn't you?
This still isn't a good plan, because you're like to get hacked if you delay fixing your code. But at least it spreads out the work over time.
P.S.: You commented that SQL injection may not have been a thing 15 years ago, but in fact:
The first public discussions of SQL injection started appearing around 1998; for example, a 1998 article in Phrack Magazine.
That's 20 years ago!
See https://en.wikipedia.org/wiki/SQL_injection#History
回答2:
Final update 5/11/2018:
Ok, here's my final answer to my own question, meticulously constructed over several weeks and tested for two months on my active e-commerce website. It works marvelously.
This also thwarts other types of non-SQL-injection attacks, such as attempts to inject bogus blog posts and other attempts to inject global variables with urls and other detritus.
//************ Foil SQL injection attacks early by validating the URL and parameters ********
//*** Rejecting a bunch of special characters - make sure to change in both places if you change this!
function VerifyURL()
{
global $URL_LOG;
global $BOGUSURL_LOG;
$RejectChars = "'\"%;\\/()[]"; //* If you change this, also change the Javascript below
$SleepTime = rand(2, 15); //* Seconds to sleep to slow down the hackers (random to confuse them)
//* REQUEST_URI breaks down to: SCRIPT_NAME, PATH_INFO, QUERY_STRING
$UrlParms = $_SERVER['REQUEST_URI'];
$ScriptName = $_SERVER['SCRIPT_NAME'];
$PathInfo = $_SERVER['PATH_INFO'];
$QueryString = $_SERVER['QUERY_STRING'];
$ClientIPAddress = str_pad($_SERVER['REMOTE_ADDR'], 15);
//* We don't use PATH_INFO (extra "/something/" after the SCRIPT_NAME) so this is always BOGUS
if (isset($PathInfo))
{
LogToFileOnly($ClientIPAddress." *BOGUS PATH_INFO: ".$UrlParms, $URL_LOG);
LogToFileOnly($ClientIPAddress." *BOGUS PATH_INFO: ".$UrlParms, $BOGUSURL_LOG);
if (!empty($_POST)) //* Log any POST data, too, to help analyze the intent of this attack
{
LogArrayToFileOnly($ClientIPAddress." *BOGUS POST Array:", $_POST, $URL_LOG);
LogArrayToFileOnly($ClientIPAddress." *BOGUS POST Array:", $_POST, $BOGUSURL_LOG);
}
sleep($SleepTime); //* Slow down the hackers
die();
}
//* Look for unusual characters that should not be in the URL and abort
$FoundAnomalies = (strpbrk($QueryString, $RejectChars));
$Exception = strpos($ScriptName, "/srch.php"); //* if this is the search page, let it through
$Exception |= strpos($ScriptName, "/amn2/"); //* if this is an admin page, let it through
if ($FoundAnomalies && !$Exception)
{
LogToFileOnly($ClientIPAddress." *BOGUS URL: ".$UrlParms, $URL_LOG);
LogToFileOnly($ClientIPAddress." *BOGUS URL: ".$UrlParms, $BOGUSURL_LOG);
if (!empty($_POST)) //* Log any POST data, too, to help analyze the intent of this attack
{
LogArrayToFileOnly($ClientIPAddress." *BOGUS POST Array:", $_POST, $URL_LOG);
LogArrayToFileOnly($ClientIPAddress." *BOGUS POST Array:", $_POST, $BOGUSURL_LOG);
}
sleep($SleepTime); //* Slow down the hackers
die();
}
else
LogToFileOnly($ClientIPAddress." Valid URL: ".$UrlParms, $URL_LOG);
//* Now look for unusual characters injected into a POST, if a POST was sent
if (!empty($_POST) && !$Exception)
{
foreach ($_POST as $key => $value)
{
//* Validate both keys and values
$FoundAnomalies = (strpbrk($key, $RejectChars) || strpbrk($value, $RejectChars));
//$Exception = ($key == "AmnMsg"); //* if this is the admin emailing message page, let it through - we want to email urls and stuff
if ($FoundAnomalies && !$Exception)
{
//* Found an anomaly, report it and die
LogArrayToFileOnly($ClientIPAddress." *BOGUS POST Array:", $_POST, $URL_LOG);
LogToFileOnly($ClientIPAddress." Valid URL: ".$UrlParms, $BOGUSURL_LOG);
LogArrayToFileOnly($ClientIPAddress." *BOGUS POST Array:", $_POST, $BOGUSURL_LOG);
sleep($SleepTime); //* Slow down the hackers
die();
}
}
LogArrayToFileOnly($ClientIPAddress." Valid POST Array:", $_POST, $URL_LOG);
}
}
//*** This code is added near the bottom of the page, and is for javascript filtering, but could be for other purposes
function FinalHTMLCode()
{
//* Attach a filter to every text input field to filter prohibited characters using javascript
echo '
<script>
//* Set the key filtering for every text type input field in the entire page
var node = document.querySelectorAll("input[type=text],input[type=password],textarea");
for (var i = 0, len = node.length; i < len; i++)
{
node[i].addEventListener("keyup", OnKeyUpEvent); //* Filter later on keypresses (and paste)
FilterInputChars(node[i]); //* Do the filtering immediatly, too
}
function OnKeyUpEvent()
{
FilterInputChars(this);
}
function FilterInputChars(textfield)
{
//* Remove prohibited characters globally in this field - also works when user pastes text!
textfield.value=textfield.value.replace(/[\\\'\"%\;\\\\/()\[\]]/g,\'\');
}
</script>
'; //* End echo
}
The number one benefit to this approach is that it detects hacking attempts early in the processing, and just die()s, therefore causing no additional cpu load of opening databases, etc., and no further information to the hacker about why the attempt failed. I also added code to confuse an active hacker by delaying the response randomly (see sleep()), so he thinks he's accomplishing something.
A legitimate user must not enter these prohibited characters into forms, so I have set up some Javascript that automatically filters all of the special characters. You can place this single line of code near the bottom of your HTML and it will automatically attach the Javascript to every text field and filter the characters:
<?php FinalHTMLCode(); //* Block prohibited characters from all text fields ?>
Note that the code also includes exceptions for pages where I know there might be a special character entered by a legitimate user but where there is no chance of a SQL injection attack succeeding.
Other improvements I made during this journey included the creation of a SQL web user account that did not have admin privileges, but just SELECT, INSERT, and UPDATE privileges for the database. This keeps a malicious attacker from DROPing tables or DELETEing rows or other potentially malicious activity.
来源:https://stackoverflow.com/questions/49102775/how-to-block-sql-injection-attacks-by-filtering-the-url-parameters-in-php