简体   繁体   English

需要有关SQL注入攻击的帮助

[英]need help on sql injection attack

Checking my web site with google webmaster tools I found a strange thing : 使用google网站管理员工具检查我的网站时,我发现了一件奇怪的事情:

somebody tried to use to link to my site using this (I change the real name of my site for obvious security reasons ) : 有人试图使用此链接到我的网站(出于明显的安全原因,我更改了网站的真实名称):

....://mysite.com/tarifs.php?annee=aaatoseihmt&mois=10&cours=1828

I try it and understand it was a sql injection with the results : 我尝试了一下,并了解到它是带有结果的sql注入:

Warning: mktime() expects parameter 6 to be long, string given in /home/..../public_html/..../tarifs.php on line 72 警告:mktime()期望参数6长,在第72行的/home/..../public_html/..../tarifs.php中给出的字符串

my code line 72 is : 我的代码行72是:

mktime (0, 0, 0, $mois, "01", $annee)

part of this: 部分原因:

<?php
include ("include.php");

if (!$link = mysql_connect($host, $user, $pass)) {
    echo "Could not connect to mysql";
    exit;
}

if (!mysql_select_db($bdd, $link)) {
    echo "Could not select database";
    exit;
}

mysql_query("SET NAMES 'utf8'");

$annee = "";
$mois = "";
$stage = "";

if (isset($_GET['annee'])) {$annee=$_GET['annee'];}
if (isset($_GET['mois'])) {$mois=$_GET['mois'];}
if (isset($_GET['stage'])) {$stage=$_GET['stage'];}

if($annee == "")
{

    $annee = date("Y");
}

if($mois == "")
{

    $mois = date("m");
}


$date_du_jour = date("d")."-".date("m")."-".date("Y");

if($mois == "12")
{
    $mois_precedent = "11";
    $mois_suivant = "01";
    $annee_mois_precedent = $annee;
    $annee_mois_suivant = $annee + 1;
}
elseif($mois == "01")
{
    $mois_precedent = "12";
    $mois_suivant = "02";
    $annee_mois_precedent = $annee - 1;
    $annee_mois_suivant = $annee;
}
else
{
    $mois_precedent = sprintf("%02s", $mois-1);
    $mois_suivant = sprintf("%02s", $mois+1);
    $annee_mois_precedent = $annee;
    $annee_mois_suivant = $annee;
}


$jour_en_cours = date("d");

$mois_francais = array("Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre");

$dt_deb_genere = $annee."-".$mois."-01";
$dt_fin_genere = $annee_mois_suivant."-".$mois_suivant."-01";

$dt_date = mktime (0, 0, 0, $mois, "01", $annee);
$jour_de_la_semaine = date("w", $dt_date);
?>

what can I do to protect my site against this ? 我该怎么做才能保护我的网站免受此侵害?

I tried to understand how to it with "similar question" but I think I am to new to php and mysql to be able to understand.So any help is really great ! 我试图用“类似的问题”来理解它,但是我认为我对php和mysql还是陌生的。所以任何帮助都很棒!

Thanks if you can help on this ! 谢谢您的帮助! I worked hard for months now on my site and don't want to lose my business. 我在自己的网站上努力工作了几个月,不想失去自己的生意。

.blc. .blc。


THEN !!! 然后 !!! I have made few little change after the code provided by Lucanos (THANKS !!!!) :-) : 在Lucanos提供的代码之后,我几乎没有做任何更改(谢谢!!!):-):

<?php
include ("include.php");

if (!$link = mysql_connect($host, $user, $pass)) {
    echo "Could not connect to mysql";
exit;
}

if (!mysql_select_db($bdd, $link)) {
echo "Could not select database";
exit;
}

mysql_query("SET NAMES 'utf8'");

$annee = '';
$mois = '';
$stage = '';

if( isset( $_GET['annee'] ) )
{
$annee = preg_replace( '/\D/' , '' , $_GET['annee'] );
if( !$annee || !( $annee<=2015 && $annee>=2013 ) )
// Allows you to set an expected range for this value
// code here expects a number between 2013 and 2015 inclusive
$annee = '';
}

if( isset( $_GET['mois'] ) )
{
$mois = preg_replace( '/\D/' , '' , $_GET['mois'] );
if( !$mois || !( $mois<=12 && $mois>=1 ) )
// I assume this is the Month, with a range of 1 to 12
$mois = '';
}

if (isset($_GET['stage'])) {$stage=$_GET['stage'];}

if($annee == '')
{
// Récupération de l'année en cours
$annee = date('Y');
}

if($mois == '')
{
// Récupération du mois en cours
$mois = date('m');
}

// Récupération de la date du jour

$date_du_jour = date( 'd-m-Y' );

if($mois == '12')
{
$mois_precedent = '11';
$mois_suivant = '01';
$annee_mois_precedent = $annee;
$annee_mois_suivant = $annee + 1;
}
elseif($mois == '01')
{
$mois_precedent = '12';
$mois_suivant = '02';
$annee_mois_precedent = $annee - 1;
$annee_mois_suivant = $annee;
}
else
{
$mois_precedent = sprintf('%02s', $mois-1);
$mois_suivant = sprintf('%02s', $mois+1);
$annee_mois_precedent = $annee;
$annee_mois_suivant = $annee;
}

// Récupération du jours en cours
$jour_en_cours = date('d');

$mois_francais = array(
'Janvier' , 'Février' , 'Mars' ,
'Avril' , 'Mai' , 'Juin' ,
'Juillet' , 'Août' , 'Septembre' ,
'Octobre' , 'Novembre' , 'Décembre'
);

$dt_deb_genere = "{$annee}-{$mois}-01";
$dt_fin_genere = "{$annee_mois_suivant}-{$mois_suivant}-01";

$dt_date = mktime( 0 , 0 , 0 , $mois*1 , 1 , $annee*1 );
$jour_de_la_semaine = date( 'w' , $dt_date );
?>

tried (with no success until now) to add a condition testing if "stage" exist in data base to avoid a call like stage=200 which do not exist ans display an empty calendar in the page. 尝试(到目前为止没有成功)添加条件测试,以便在数据库中存在“ stage”,以避免诸如stage = 200之类的调用不存在,并且在页面中显示空日历。 But in final I miss something here (I didn't include it in the past code ) 但最终我错过了一些东西(我没有在过去的代码中包括它)

$sql_stage = "select * from data where type_data = 'STAGE' and ind_valide = 1 and ind_etat = 1 order by sous_titre, id_type_1, ordre";
$result_stage = mysql_query($sql_stage, $link);
$existingstage = '';


while ($row_stage = mysql_fetch_array($result_stage))
{
$existingstage = $row_stage["id_data"];

if( isset( $_GET['stage'] ) )
{
    $stage = preg_replace( '/\D/' , '' , $_GET['stage'] );

    if( !$stage || !( $stage= $existingstage ) )

    $stage = '';
}
}

Never Trust User Input 永不信任用户输入

Anytime you use a value from a form, or extracted from a URL, make sure that you test it, sanitise it and/or escape it before you use it. 每当您使用来自表单的值或从URL提取的值时,请在使用前确保对其进行测试,清理和/或转义。 Anywhere. 无处不在。

So, for instance, with your code, I would edit it as follows: 因此,例如,使用您的代码,我将对其进行如下编辑:

<?php
include ("include.php");

// Might be worth putting this into the "include.php" file, or a function
// to do the same thing. Especially if you connect to the DB regularly.
if (!$link = mysql_connect($host, $user, $pass)) {
    echo "Could not connect to mysql";
    exit;
}

// Same as above...
if (!mysql_select_db($bdd, $link)) {
    echo "Could not select database";
    exit;
}

// And again...
mysql_query("SET NAMES 'utf8'");


$annee = '';
$mois = '';
$stage = '';

if( isset( $_GET['annee'] ) )
{
    $annee = preg_replace( '/\D/' , '' , $_GET['annee'] );
    if( !$annee || !( $annee<=2020 && $annee>=1970 ) )
        // Allows you to set an expected range for this value
        // My code here expects a number between 1970 and 2020 inclusive
        $annee = '';
}
if( isset( $_GET['mois'] ) )
{
    $mois = pre_replace( '/\D/' , '' , $_GET['mois'] );
    if( !$mois || !( $mois<=12 && $mois>=1 ) )
        // I assume this is the Month, with a range of 1 to 12
        $mois = '';
}
if( isset( $_GET['stage'] ) )
{
    $stage = pre_replace( '/\D/' , '' , $_GET['stage'] );
    if( !$stage || !( $stage<=100 && $stage>=0 ) )
        // Again, assuming 1-100
        $stage = '';
}

if( $annee=='' )
    $annee = date( 'Y' );

if( $mois=='' )
    $mois = date( 'n' );

$date_du_jour = date( 'd-m-Y' );

if( $mois=='12' )
{
    $mois_precedent = '11';
    $mois_suivant = '01';
    $annee_mois_precedent = $annee;
    $annee_mois_suivant = $annee + 1;
}
elseif( $mois=='01' )
{
    $mois_precedent = '12';
    $mois_suivant = '02';
    $annee_mois_precedent = $annee - 1;
    $annee_mois_suivant = $annee;
}
else
{
    $mois_precedent = sprintf( '%02s' , $mois-1 );
    $mois_suivant = sprintf( '%02s' , $mois+1 );
    $annee_mois_precedent = $annee;
    $annee_mois_suivant = $annee;
}


$jour_en_cours = date( 'd' );

$mois_francais = array(
    'Janvier' , 'Février' , 'Mars' ,
    'Avril' , 'Mai' , 'Juin' ,
    'Juillet' , 'Août' , 'Septembre' ,
    'Octobre' , 'Novembre' , 'Décembre'
);

$dt_deb_genere = "{$annee}-{$mois}-01";
$dt_fin_genere = "{$annee_mois_suivant}-{$mois_suivant}-01";

$dt_date = mktime( 0 , 0 , 0 , $mois*1 , 1 , $annee*1 );
$jour_de_la_semaine = date( 'w' , $dt_date );

?>

For the future, use prepared statements. 为了将来,请使用准备好的语句。 They allow you to send the query first and send the values afterwards which prevents injection. 它们允许您先发送查询,然后再发送值,以防止注入。 I prefer using PDO . 我更喜欢使用PDO

Anyway, rule number one in databases: validate or sanitize user input. 无论如何,数据库中的第一条规则:验证或清除用户输入。


If you are sure that the input should be a number, just force it to a number: 如果您确定输入应为数字,则将其强制为数字:

$number = intval($_GET['number']);

In this case, if the user changes it to a bit of text, intval() will return 0. 在这种情况下,如果用户将其更改为一些文本,则intval()将返回0。


For the mysql_ functions, if the input is a string, use mysql_real_ecsape_string() : 对于mysql_函数,如果输入是字符串,请使用mysql_real_ecsape_string()

$string = mysql_real_eascape_string($_GET['string']);

This will escape all "unwanted" characters that could affect your SQL query. 这将转义所有可能影响您的SQL查询的“不需要的”字符。 However, this function is compromised too. 但是,此功能也受到损害。

Use prepared statements and parameterized queries. 使用准备好的语句和参数化查询。 These are SQL statements that are sent to and parsed by the database server separately from any parameters. 这些是独立于任何参数发送到数据库服务器并由数据库服务器解析的SQL语句。 This way it is impossible for an attacker to inject malicious SQL. 这样,攻击者就不可能注入恶意SQL。

You basically have two options to achieve this: 您基本上有两种选择可以实现此目的:

  1. Using PDO 使用PDO
  2. Using mysqli 使用mysqli

Required : 必填:

  • Protect your database layer using more protective functions such as mysqli 使用更多保护功能(例如mysqli)保护数据库层
  • Escape all of your statements 转义所有陈述
  • Validate all of your inputs 验证所有输入

Optional/lazy : 可选/懒惰:

  • Get rid of the $_GET variables and either use $_POST or $_SESSION 摆脱$ _GET变量,并使用$ _POST或$ _SESSION

Try: 尝试:

if($annee == "" || intval($annee) == 0 ) {
    $annee = date("Y");
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM