ホームページ  >  記事  >  バックエンド開発  >  PHP の弱い型の安全性の問題について話す

PHP の弱い型の安全性の問題について話す

little bottle
little bottle転載
2019-04-27 11:37:303000ブラウズ

この記事の編集者は、PHP の弱い型付けについてお話したいと考えています。PHP の弱い型付けは、コードを書くときにプログラマに大きな利便性をもたらしますが、すべてには 2 つの側面があります。次に、エディターでそれについて学びましょう。

0x00 弱い型に関する予備調査

PHP のシンプルさと強力さを疑問視する人はいません。開発者が使用できる多くの機能を提供します。そのうちの 1 つは弱いタイプのメカニズムです。

弱い型メカニズムでは、このような操作を実行できます。

<?php
$var = 1;
$var = array();
$var = "string";
?>

php は、受け取った変数の型を厳密にチェックせず、変数の型を自由に変換することもできます。

たとえば、$a == $b

$a = null; $b = false; //为真
$a = &#39;&#39;; $b = 0; //同样为真

の比較では、PHP カーネルの開発者は当初、より効率的に宣言を必要としないこのシステムをプログラマに使用してもらいたいと考えていました。開発では、プログラマーの不正によりプログラム内の変数が頻繁にエラーを報告することを防ぐために、ほぼすべての組み込み関数や基本構造で緩やかな比較や変換が多用されていますが、これにはセキュリティ上の問題が伴います。

0x02 知識の準備 PHP カーネルの Zval 構造

PHP で宣言された変数は、構造 zval を使用して ZE に保存されます。 zval は zend/zend.h

typedef struct _zval_struct zval;  
struct _zval_struct {  
  /* Variable information */  
  zvalue_value value; /* value */  
  zend_uint refcount__gc;  
  zend_uchar type;/* active type */  
  zend_uchar is_ref__gc;  
};  
typedef union _zvalue_value {  
  long lval;  /* long value */  
  double dval;/* double value */  
  struct {  
    char *val;  
    int len;  
  } str;  
  HashTable *ht;  /* hash table value */  
  zend_object_value obj;  
} zvalue_value;

で定義されており、PHP は type を通じて変数の型を決定し、それを value に格納します

上記は、PHP カーネルにおける弱い型のカプセル化です。また、後で説明するすべての原則と基礎でもあります。

0x03 変数の強制変換これまでの理解により、zval.type が zval.value に格納される型を決定することがわかりました。

ソース コードが制限のない型比較や数学的演算を実行すると、zval.type が変更される可能性があり、同時に zval.value の内容も変更される可能性があります。

int が string と一致する場合

cp.1 数学的演算

PHP が数学的計算を実行する場合

ar_dump(0 == &#39;0&#39;); // true
var_dump(0 == &#39;abcdefg&#39;); // true  
var_dump(0 === &#39;abcdefg&#39;); // false
var_dump(1 == &#39;1abcdef&#39;); // true

一方の比較パラメータが整数の場合、もう一方のパラメータは強制的に整数に変換されます。

文字列部分

intval と整数部分を比較するのと同じです。実際、これは zval.type の内容を変更します。特に '1assd' の変換された値が 1 であることに注意してください。 'asdaf' は 0

これは、intval が数値ではない最初の単位から始まることも意味します

すべてにも

var_dump(intval(&#39;3389a&#39;));//输出3389
があります

この例では、常に Don であることがわかります。次のコードは信じられません

if($a>1000){    
mysql_query(&#39;update ... .... set value=$a&#39;)
}

この時点でブランチに入るのは整数であると考えています

実際には、$a は 1001/**/union...

である可能性があります。

cp.2 文の条件の緩い判定

例えば、PHPのswitchは緩い比較を使っていますが、$はintvalで自動的に0になります。この場合、インクルードされるまで実行され、最後に必要な関数まで実行されます。正常にインクルードされた

<?php
if (isset($_GET[&#39;which&#39;]))
{
  $which = $_GET[&#39;which&#39;];
  switch ($which)
  {
  case 0:
  case 1:
  case 2:
    require_once $which.&#39;.php&#39;;
    break;
  default:
    echo GWF_HTML::error(&#39;PHP-0817&#39;, &#39;Hacker NoNoNo!&#39;, false);
    break;
  }

cp.3 関数

var_dump(in_array("abc", $array));
の大まかな判断は次のとおりです。 in_array — 配列が次であるかどうかを確認します。検索する値の値パラメータ

needle があります。

注: 針が文字列の場合、比較では大文字と小文字が区別されます。この配列を干し草の山にします。

strict 3 番目のパラメータ strict の値が TRUE の場合、in_array() 関数は針のタイプが干し草の山のものと同じかどうかもチェックします。

ご覧のとおり、strict を追加するだけで型が厳密に比較されます。では、もう一度 ××× と文字列を比較するとどうなるでしょうか。

var_dump(in_array("abc", $array1));</br>
var_dump(in_array("1bc", $array2));

配列の各値を走査し、「==」比較を実行します (「厳密が設定されている場合は === を使用します)

結果は明らかです

# array1 の値が 0 の場合、最初の戻り値は true になります。 //intval('abc')=0

array2 の値が 1 の場合、2 番目の戻り値は true になります。 be True//intval('1bc')=1

同じ原則が array_search にも当てはまります

ここでのアプリケーションは非常に広範囲にわたるため、

多くのプログラマが配列の値をチェックします,

その後、構築された int 0 または 1 を完全に使用して検出関数を騙し、true を返すようにすることができます

要約すると、PHP が int であると考えるすべての場所に文字列を入力します。

$a = &#39;asdfgh&#39;;//字符串类型的a</br>
echo $a[2];  //根据php的offset 会输出&#39;d&#39;</br>
echo $a[x];  //根据php的预测,这里应该是int型,那么输入string,就会被intval成为0 也就是输出&#39;a&#39;

When the array meets string

のように変換を強制される ドイツの ctf でこの例に遭遇しました。非常に興味深いものです。前に話した内容これらはすべて string と int の間の比較です。

それでは、配列が int または string と遭遇したときにどのような化学反応が起こるでしょうか?

PHP マニュアルから、

配列を int/浮動小数点型 float に変換すると要素の数が返され、

bool を変換すると要素が存在するかどうかが返されることがわかります。配列; 文字列に変換すると「配列」が返され、警告がスローされます。

それでは、実際の応用とは何でしょうか?

if(!strcmp($c[1],$d) && $c[1]!==$d){
...
}

このブランチでは、strcmp 関数の比較によって 2 つが等しい必要があり、「==」に入るには 2 つが等しくないことが必要であることがわかります。

strcmp() 関数は 2 つの文字列を比較します。

この関数は次を返します:

0 - 2 つの文字列が等しい場合

e8c463539e946e0c062eccbe6513ebe90 - if string1 Greater than string2

ここでの strcmp 関数は、実際には 2 つの変数を ASCII に変換し、その後、数学的な減算を実行して int の差を返します。

つまり、比較するために「a」と「a」を入力した結果は 0

それでは、$array と ‘a' を比較するとどうなるでしょうか?

http://localhost:8888/1.php?a[]=1
var_dump(strcmp($_GET[a],&#39;a&#39;));

現時点では、php は null を返しました。

言い換えれば、この関数をエラーにして、関数チェックをバイパスして常に true になるようにします。

0x04 常に弱い型に注意してください

プログラマにとって、弱い型はコードを記述するときに非常に便利です。プログラマーは $array =array(); という習慣を忘れてしまいます。すべての入力は有害であると言われています

実際、すべての入力の型も疑わしいと言えます。弱い型指定の PHP では、比較関数や数学演算を決して信頼しないでください。そうでなければ、あなたは間違いなくphpに裏切られた人です。

関連チュートリアル: PHP ビデオ チュートリアル

以上がPHP の弱い型の安全性の問題について話すの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は51cto.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。