ホームページ  >  記事  >  バックエンド開発  >  PHP セキュリティを開発する際に考慮すべきことは何ですか?

PHP セキュリティを開発する際に考慮すべきことは何ですか?

王林
王林転載
2019-09-09 18:00:443579ブラウズ

PHP セキュリティを開発する際に考慮すべきことは何ですか?

PHP セキュリティを開発する際には何を考慮する必要がありますか?

1, サイトの機密ディレクトリの漏洩を避けるために、サイト全体の構造を把握する

初めてコードを書き始めたとき、私はこう思いました。多くの古いソース コードと同様に、index.php、register.php、login.php をルート ディレクトリに置き、ユーザーが登録ページをクリックすると、http://localhost/register.php## にジャンプします。 #。このようなコード構造では、最大の問題はセキュリティではなく、コードの拡張と移植です。

コードを作成する過程で、コードを変更する必要が生じることがよくありますが、このとき、コードに統一されたエントリ ポイントがない場合、多くの箇所を変更する必要がある可能性があります。後で、emlog コードを少し読んだところ、Web サイトの実際のフロントエンド コードはテンプレート ディレクトリにあり、ルート ディレクトリにはエントリ ポイント ファイルと設定ファイルだけがあることがわかりました。そこでひらめき、Webサイト全体の構造を変更しました。

Web サイトのルート ディレクトリにエントリ ポイント ファイルを配置し、Web サイト全体のすべてのページを管理できるようにします。このとき、登録ページは

http://localhost/?act=register になります。 、どのページも act のパラメータにすぎません。このパラメータを取得した後、スイッチを使用して、含めるファイル コンテンツを選択します。このエントリ ポイント ファイルには、Web サイトの絶対パス、Web サイトのアドレス、データベース ユーザーのパスワードなどの定数の定義を含めることもできます。将来的には、スクリプトを作成するときに、相対パスの代わりに絶対パスを使用するようにします (そうしないと、スクリプトの場所が変更されると、コードも変更されます)。この絶対パスは、エントリ ポイント ファイルの定義から取得されます。

もちろん、セキュリティの観点から、エントリ ポイント ファイルはバックエンド アドレスを隠すこともできます。この

http://localhost/?act=xxx のようなアドレスは、バックグラウンドで絶対パスを公開せず、コードをあまり変更せずに頻繁に変更することもできます。エントリ ポイント ファイルは、管理者以外のページの表示が許可されていない Web サイトのバックエンドなど、訪問者の身元を確認することもできます。エントリ ポイント ファイルで本人確認を行うことができますが、ログインしていない場合は 404 ページが出力されます。

エントリ ポイント ファイルでは、すべての非エントリ ポイント ファイルの前に次の文を追加しました:

<?php 
if(!defined(&#39;WWW_ROOT&#39;))
 {
header("HTTP/1.1 404 Not Found");
 exit;
 } 
?>

WWW_ROOT はエントリ ポイントで定義した定数です。このページの絶対パス (

http://localhost/register.php) を指定すると、404 エラーが出力されます。エントリ ポイント (http://localhost/?act=register) 経由でのみアクセスします。 ) 次のコードを実行します。

2. SQL インジェクションを避けるためにプリコンパイルされたステートメントを使用する

インジェクションは以前は大きな問題でしたが、近年、誰もがこの問題に注目しているため、それで徐々に良くなってきています。

Wu Hanqing 氏が Web White Hat でよく言っていますが、実際、SQL インジェクションや XSS などの多くの脆弱性は、「データ」と「コード」を区別しません。 「コード」はプログラマーが記述するもの、「データ」はユーザーが変更できるものです。 SQL ステートメント

select * from admin where username='admin'password='xxxxx' を記述する場合、admin と xxxxx はデータであり、ユーザーが入力したユーザー名とパスワードですが、処理が行われない場合、ユーザー入力は「コード」(「または ''=」など)である可能性があり、脆弱性が生じます。ユーザーが「コード」にアクセスできないようにしてください。

PHP には、mysql データベース用の 2 つのモジュール、mysql と mysqli があります。Mysqli は、mysql の改善を意味します。 mysql の改良版であるこのモジュールには、「プリコンパイル」の概念が含まれています。上記の SQL ステートメントと同様に、次のように変更します。

select * from admin where username='?' Password='?' これは SQL ステートメントではありませんが、mysqli のプリコンパイル機能を使用して次のように実行できます。最初に stmt オブジェクトにコンパイルされ、後でユーザーがアカウントとパスワードを入力した後、stmt->bind_param を使用して、ユーザーが入力した「データ」をこれら 2 つの疑問符の位置にバインドします。このように、ユーザーが入力した内容はあくまで「データ」であり、「コード」にすることはできません。

これら 2 つの疑問符は、「データ」の場所と SQL ステートメントの構造を定義します。すべてのデータベース操作を 1 つのクラスにカプセル化でき、すべての SQL ステートメントの実行がプリコンパイルされます。これにより、Wu Hanqing が最も推奨するソリューションでもある SQL インジェクションが完全に回避されます。

以下は、mysqli を使用したコード部分です (関数の実行が成功したか失敗したかを決定するコードはすべて省略していますが、重要ではないという意味ではありません):

<?php
//用户输入的数据
$name = &#39;admin&#39;;
$pass = &#39;123456&#39;;
//首先新建mysqli对象,构造函数参数中包含了数据库相关内容。
$conn = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_PORT);
//设置sql语句默认编码
$this->mysqli->set_charset("utf8");
//创建一个使用通配符的sql语句
$sql = &#39;SELECT user_id FROM admin WHERE username=? AND password=?;&#39;;
//编译该语句,得到一个stmt对象.
$stmt = $conn->prepare($sql);
/********************之后的内容就能重复利用,不用再次编译*************************/
//用bind_param方法绑定数据
//大家可以看出来,因为我留了两个?,也就是要向其中绑定两个数据,所以第一个参数是绑定的数据的类型(s=string,i=integer),第二个以后的参数是要绑定的数据
$stmt->bind_param(&#39;ss&#39;, $name, $pass);
//调用bind_param方法绑定结果(如果只是检查该用户与密码是否存在,或只是一个DML语句的时候,不用绑定结果)
//这个结果就是我select到的字段,有几个就要绑定几个
$stmt->bind_result($user_id);
//执行该语句
$stmt->execute();
//得到结果
if($stmt->fetch()){
 echo &#39;登陆成功&#39;;
 //一定要注意释放结果资源,否则后面会出错
 $stmt->free_result();
 return $user_id; //返回刚才select到的内容
}else{echo &#39;登录失败&#39;;}
?>

3. 防止 XSS コード、Cookie を使用する必要がない場合は、使用しないでください

私は自分の Web サイトで Cookie を使用しておらず、アクセス許可を厳しく制限しているため、 XSS のリスクは比較的小さいです。

xss の防御にも同様の原則が適用され、「コード」と「データ」の関係を適切に扱います。もちろん、ここでのコードは JavaScript コードまたは HTML コードを指します。ユーザーが制御できるコンテンツについては、htmlspecialchars などの関数を使用してユーザーが入力したデータを処理し、JavaScript でページにコンテンツを出力するように注意する必要があります。

4. ユーザー権限を制限し、CSRF を防止します

现在脚本漏洞比较火的就是越权行为,很多重要操作使用GET方式执行,或使用POST方式执行而没有核实执行者是否知情。

CSRF很多同学可能比较陌生,其实举一个小例子就行了:

A、B都是某论坛用户,该论坛允许用户“赞”某篇文章,用户点“赞”其实是访问了这个页面:http://localhost/?act=support&articleid=12。这个时候,B如果把这个URL发送给A,A在不知情的情况下打开了它,等于说给articleid=12的文章赞了一次。

所以该论坛换了种方式,通过POST方式来赞某篇文章。

<form action="http://localhost/?act=support" method="POST">
 <input type="hidden" value="12" name="articleid">
 <input type="submit" value="赞">
</form>

可以看到一个隐藏的input框里含有该文章的ID,这样就不能通过一个URL让A点击了。但是B可以做一个“极具诱惑力”的页面,其中某个按钮就写成这样一个表单,来诱惑A点击。A一点击,依旧还是赞了这篇文章。

最后,该论坛只好把表单中增加了一个验证码。只有A输入验证码才能点赞。这样,彻底死了B的心。

但是,你见过哪个论坛点“赞”也要输入验证码?

所以吴翰清在白帽子里也推荐了最好的方式,就是在表单中加入一个随机字符串token(由php生成,并保存在SESSION中),如果用户提交的这个随机字符串和SESSION中保存的字符串一致,才能赞。

在B不知道A的随机字符串时,就不能越权操作了。

我在网站中也多次使用了TOKEN,不管是GET方式还是POST方式,通常就能抵御99%的CSRF估计了。

5、严格控制上传文件类型

上传漏洞是很致命的漏洞,只要存在任意文件上传漏洞,就能执行任意代码,拿到webshell。

我在上传这部分,写了一个php类,通过白名单验证,来控制用户上传恶意文件。在客户端,我通过javascript先验证了用户选择的文件的类型,但这只是善意地提醒用户,最终验证部分,还是在服务端。

白名单是必要的,你如果只允许上传图片,就设置成array('jpg','gif','png','bmp'),当用户上传来文件后,取它的文件名的后缀,用in_array验证是否在白名单中。

在上传文件数组中,会有一个MIME类型,告诉服务端上传的文件类型是什么,但是它是不可靠的,是可以被修改的。在很多存在上传漏洞的网站中,都是只验证了MIME类型,而没有取文件名的后缀验证,导致上传任意文件。

所以我们在类中完全可以忽略这个MIME类型,而只取文件名的后缀,如果在白名单中,才允许上传。

当然,服务器的解析漏洞也是很多上传漏洞的突破点,所以我们尽量把上传的文件重命名,以“日期时间+随机数+白名单中后缀”的方式对上传的文件进行重命名,避免因为解析漏洞而造成任意代码执行。

6、加密混淆javascript代码,提高攻击门槛

很多xss漏洞,都是黑客通过阅读javascript代码发现的,如果我们能把所有javascript代码混淆以及加密,让代码就算解密后也是混乱的(比如把所有变量名替换成其MD5 hash值),提高阅读的难度。

7、使用更高级的hash算法保存数据库中重要信息

这个硬盘容量大增的时期,很多人拥有很大的彩虹表,再加上类似于cmd5这样的网站的大行其道,单纯的md5已经等同于无物,所以我们迫切的需要更高级的hash算法,来保存我们数据库中的密码。

所以后来出现了加salt的md5,比如discuz的密码就是加了salt。其实salt就是一个密码的“附加值”,比如A的密码是123456,而我们设置的salt是abc,这样保存到数据库的可能就是md5('123456abc'),增加了破解的难度。

但是黑客只要得知了该用户的salt也能跑md5跑出来。因为现在的计算机的计算速度已经非常快了,一秒可以计算10亿次md5值,弱一点的密码分把钟就能跑出来。

所以后来密码学上改进了hash,引进了一个概念:密钥延伸。说简单点就是增加计算hash的难度(比如把密码用md5()函数循环计算1000次),故意减慢计算hash所用的时间,以前一秒可以计算10亿次,改进后1秒只能计算100万次,速度慢了1000倍,这样,所需的时间也就增加了1000倍。

那么对于我们,怎么使用一个安全的hash计算方法?大家可以翻阅emlog的源码,可以在include目录里面找到一个HashPaaword.php的文件,其实这就是个类,emlog用它来计算密码的hash。

このクラスには特徴があります。計算されるハッシュ値は毎回異なります。そのため、ハッカーはレインボー テーブルなどの方法でパスワードを解読することはできません。ハッカーは、このクラスの checkpassword メソッドを使用して、入力されたパスワードの正しさを返すことしかできません。ユーザー。また、この機能はハッシュの計算時間を意図的に長くするため、ハッカーが取得したハッシュ値を解読することが困難になります。

最新のphp5.5ではこのハッシュアルゴリズムが正式な機能となり、将来的にはこの機能を利用してパスワードをハッシュ化できるようになります

8. 認証コードセキュリティ

検証コードは通常、PHP スクリプトによって生成されたランダムな文字列で、GD ライブラリによって処理されて画像化されます。実際の検証コード文字列は SESSION に保存され、生成された画像がユーザーに表示されます。ユーザーが検証コードを入力して送信すると、SESSION 内の検証コードがサーバー上で比較されます。

これを見て、私が以前犯した間違いを思い出しました。検証コードの比較が完了した後、それが正しいか間違っているかにかかわらず、SESSIONをクリアしませんでした。これにより問題が発生します。ユーザーが初めて検証コードを送信すると、2 回目以降は検証コードを生成するスクリプトにアクセスできなくなります。このとき、SESSION 内の検証コードは更新または削除されません。 、検証コードが再利用されることになりますが、検証の目的には役立ちません。

認証コードが認識されない問題について話します 私は emlog を含む WordPress プログラムをよく参考にしていますが、その認証コードは褒められたものではありません。検証コードが機械に認識された後に多くのスパムコメントが生成されたため、その後、w3cが推奨していると言われているより複雑な検証コードを使用しました。

そうですね、実際のアプリケーションで使用できるものは、私が思いつく限りたくさんあります。これは、私が独自のコードを書いている間に蓄積した、コードのセキュリティに関する洞察のほんの一部です。もっと良いアイデアがある場合は、私と連絡してください。皆さんもより安全なコードを書けるようになってほしいと思います。

上記の内容は参考用です。

推奨ビデオ チュートリアル: PHP ビデオ チュートリアル

以上がPHP セキュリティを開発する際に考慮すべきことは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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