需要帮助sql注入攻击

时间:2013-09-12 09:25:59

标签: php sql code-injection mktime

使用Google网站管理员工具检查我的网站我发现了一件奇怪的事情:

有人尝试使用此链接到我的网站(出于明显的安全原因,我更改了我网站的真实姓名):

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

我尝试并理解它是一个带有结果的SQL注入:

  

警告:mktime()期望参数6为long,字符串为   /home/..../public_html/..../tarifs.php   在第72行

我的代码第72行是:

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

部分内容:

<?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);
?>

我可以做些什么来保护我的网站免受此事?

我试图理解如何使用“类似问题”,但我认为我是新手到php和mysql才能理解。所以任何帮助都非常棒!

谢谢你能帮忙解决这个问题!我现在在我的网站上努力了好几个月,不想失去我的生意。

.blc。


然后!!!在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 );
?>

尝试(直到现在没有成功)添加条件测试,如果数据库中存在“stage”以避免不存在的stage = 200之类的调用,则在页面中显示空日历。但是在决赛中我错过了一些东西(我在过去的代码中没有包含它)

$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 = '';
}
}

5 个答案:

答案 0 :(得分:1)

永远不要相信用户输入

无论何时使用表单中的值或从URL中提取值,请确保在使用之前对其进行测试,清理和/或将其转义。任何地方。

因此,例如,使用您的代码,我会按如下方式对其进行编辑:

<?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 );

?>

答案 1 :(得分:0)

将来,请使用准备好的陈述。它们允许您先发送查询,然后发送值以防止注入。我更喜欢使用PDO

无论如何,数据库中的第一条规则:验证或清理用户输入。


如果您确定输入应该是数字,只需将其强制为数字:

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

在这种情况下,如果用户将其更改为一些文本,intval()将返回0.


对于mysql_函数,如果输入是字符串,请使用mysql_real_ecsape_string()

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

这将逃脱所有&#34;不需要的&#34;可能影响SQL查询的字符。但是,这个功能也受到了损害。

答案 2 :(得分:0)

使用预准备语句和参数化查询。这些是由数据库服务器与任何参数分开发送和解析的SQL语句。这样攻击者就无法注入恶意SQL。

你基本上有两个选择来实现这个目标:

  1. 使用PDO
  2. 使用mysqli

答案 3 :(得分:0)

必填:

  • 使用更多保护功能(如mysqli
  • )保护您的数据库层
  • 逃避所有陈述
  • 验证所有输入

可选/懒惰:

  • 摆脱$ _GET变量并使用$ _POST或$ _SESSION

答案 4 :(得分:0)

尝试:

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