com doc/zh: sync to en: Fix #77799: Database security information is outdated: security/database.xml

[email protected] (Bole Chen) Tue, 02 Feb 2021 02:40:57 +0000
Newsgroups php.doc.zh
Message-ID <[email protected]>
Commit:    fdedb252383beca72390f7d1040a2e9ca615a96a
Author:    Bole Chen <[email protected]>         Tue, 2 Feb 2021 10:40:57 +0800
Parents:   45036be770e3faa00326fad505276c1fa314e9a6
Branches:  master

Link:       http://git.php.net/?p=doc/zh.git;a=commitdiff;h=fdedb252383beca72390f7d1040a2e9ca615a96a

Log:
sync to en: Fix #77799: Database security information is outdated

Bugs:
https://bugs.php.net/77799

Changed paths:
  M  security/database.xml
diff_fdedb252383beca72390f7d1040a2e9ca615a96a.txt (text/plain, 9.5 KB)
diff --git a/security/database.xml b/security/database.xml
index 5b0dd267..b0cea7b6 100644
--- a/security/database.xml
+++ b/security/database.xml
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- $Revision$ -->
 <!-- $Author$ -->
-<!-- EN-Revision: n/a Maintainer: lm92 Status: ready -->
+<!-- EN-Revision: fa6c0138655159c9a360fbbf0364ac0f38274abd Maintainer: lm92 Status: ready -->
 <!-- CREDITS: dallas -->
-  <chapter xml:id="security.database" xmlns="http://docbook.org/ns/docbook">
+  <chapter xml:id="security.database" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
    <title>数据库安全</title>
 
    <simpara>
@@ -64,42 +64,57 @@
      服务器),敏感数据就可能暴露或者被滥用,除非数据库自己保护了这些信息。对数据库内的数据加密是减少这类风险的有效途径,但是只有很少的数据库提供这些加密功能。
     </simpara>
     <simpara>
-     对于这个问题,有一个简单的解决办法,就是创建自己的加密机制,然后把它用在 PHP
-     程序内。PHP 有几个扩展库可以完成这个工作,比如说
-     <link linkend="ref.mcrypt">Mcrypt</link> 和
-     <link linkend="ref.mhash">Mhash</link> 等,它们包含多种加密运算法则。脚本在插入数据库之前先把数据加密,以后提取出来时再解密。有关加密如何工作的例子请参考相关手册。
+     解决这个问题最简单的方法是创建自己的加密包,然后在 <acronym>PHP</acronym> 脚本中使用它。<acronym>PHP</acronym>
+     可以通过一些扩展来帮助你解决这个问题,比如 <link
+     linkend="book.openssl">OpenSSL</link> 和 <link
+     linkend="book.sodium">Sodium</link>,涵盖了多种加密算法。脚本在将数据插入数据库之前对其进行加密,并在检索时对其进行解密。更多关于加密工作的例子请参见参考文献。
     </simpara>
-    <simpara>
-     对某些真正隐蔽的数据,如果不需要以明文的形式存在(即不用显示),可以考虑用散列算法。使用散列算法最常见的例子就是把密码经过
-     MD5 加密后的散列存进数据库来代替原来的明文密码。参见
-     <function>crypt</function> 和 <function>md5</function>。
-    </simpara>
-    <example>
-     <title>对密码字段进行散列加密</title>
-     <programlisting role="php">
+
+    <sect2 xml:id="security.database.storage.hashing">
+    <title>Hashing</title>
+     <simpara>
+      In the case of truly hidden data, if its raw representation is not needed
+      (i.e. will not be displayed), hashing should be taken into consideration.
+      The well-known example for hashing is storing the cryptographic hash of a
+      password in a database, instead of the password itself.
+     </simpara>
+     <simpara>
+      The <link linkend="ref.password">password</link> functions
+      provide a convenient way to hash sensitive data and work with these hashes.
+     </simpara>
+     <simpara>
+      <function>password_hash</function> is used to hash a given string using the
+      strongest algorithm currently available and <function>password_verify</function>
+      checks whether the given password matches the hash stored in database.
+     </simpara>
+     <example>
+      <title>Hashing password field</title>
+      <programlisting role="php">
 <![CDATA[
 <?php
 
 // 存储密码散列
 $query  = sprintf("INSERT INTO users(name,pwd) VALUES('%s','%s');",
-            pg_escape_string($username), md5($password));
+            pg_escape_string($username),
+            password_hash($password, PASSWORD_DEFAULT));
 $result = pg_query($connection, $query);
 
 // 发送请求来验证用户密码
-$query = sprintf("SELECT 1 FROM users WHERE name='%s' AND pwd='%s';",
-            pg_escape_string($username), md5($password));
-$result = pg_query($connection, $query);
+$query = sprintf("SELECT pwd FROM users WHERE name='%s';",
+            pg_escape_string($username));
+$row = pg_fetch_assoc(pg_query($connection, $query));
 
-if (pg_num_rows($result) > 0) {
-    echo 'Welcome, $username!';
+if ($row && password_verify($password, $row['pwd'])) {
+    echo 'Welcome, ' . htmlspecialchars($username) . '!';
 } else {
-    echo 'Authentication failed for $username.';
+    echo 'Authentication failed for ' . htmlspecialchars($username) . '.';
 }
 
 ?>
 ]]>
-     </programlisting>
-    </example>
+      </programlisting>
+     </example>
+    </sect2>
    </sect1>
 
    <sect1 xml:id="security.database.sql-injection">
@@ -119,7 +134,7 @@ if (pg_num_rows($result) > 0) {
      由于在缺乏对输入的数据进行验证,并且使用了超级用户或其它有权创建新用户的数据库帐号来连接,攻击者可以在数据库中新建一个超级用户。
      <example>
       <title>
-       一段实现数据分页显示的代码……也可以被用作创建一个超级用户(PostgreSQL系统)。
+       一段实现数据分页显示的代码…… 也可以被用作创建一个超级用户(PostgreSQL 数据库)。
       </title>
       <programlisting role="php">
 <![CDATA[
@@ -153,8 +168,7 @@ insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
     </para>
     <note>
      <para>
-      <literal>--</literal> 是 SQL 的注释标记,一般可以使用来它告诉 SQL
-      解释器忽略后面的语句。
+      <literal>--</literal> 是 SQL 的注释标记,一般可以使用来它告诉 SQL 解释器忽略后面的语句。
      </para>
     </note>
     <para>
@@ -173,16 +187,15 @@ insert into pg_shadow(usename,usesysid,usesuper,usecatupd,passwd)
 <?php
 
 $query  = "SELECT id, name, inserted, size FROM products
-                  WHERE size = '$size'
-                  ORDER BY $order LIMIT $limit, $offset;";
+           WHERE size = '$size'";
 $result = odbc_exec($conn, $query);
 
 ?>
 ]]>
       </programlisting>
      </example>
-     可以在原来的查询的基础上添加另一个 <literal>SELECT</literal>
-     查询来获得密码:
+     可以在原来的查询的基础上添加另一个
+     <literal>SELECT</literal> 查询来获得密码:
      <informalexample>
       <programlisting role="sql">
 <![CDATA[
@@ -222,11 +235,11 @@ $query = "UPDATE usertable SET pwd='$pwd' WHERE uid='$uid';";
 <![CDATA[
 <?php
 
-// $uid == ' or uid like'%admin%'; --
-$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%'; --";
+// $uid: ' or uid like '%admin%
+$query = "UPDATE usertable SET pwd='...' WHERE uid='' or uid like '%admin%';";
 
-// $pwd == "hehehe', admin='yes', trusted=100 "
-$query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
+// $pwd: hehehe', trusted=100, admin='yes
+$query = "UPDATE usertable SET pwd='hehehe', trusted=100, admin='yes' WHERE
 ...;";
 
 ?>
@@ -237,7 +250,7 @@ $query = "UPDATE usertable SET pwd='hehehe', admin='yes', trusted=100 WHERE
     <para>
      下面这个可怕的例子将会演示如何在某些数据库上执行系统命令。
      <example>
-     <title>攻击数据库所在主机的操作系统(MSSQL Server)</title>
+     <title>攻击数据库所在主机的操作系统(MSSQL Server 数据库)</title>
       <programlisting role="php">
 <![CDATA[
 <?php
@@ -259,8 +272,8 @@ $result = mssql_query($query);
 <?php
 
 $query  = "SELECT * FROM products
-                    WHERE id LIKE '%a%'
-                    exec master..xp_cmdshell 'net user test testpass /ADD'--";
+           WHERE id LIKE '%a%'
+           exec master..xp_cmdshell 'net user test testpass /ADD' --%'";
 $result = mssql_query($query);
 
 ?>
@@ -277,6 +290,15 @@ $result = mssql_query($query);
       虽然以上的例子是针对某一特定的数据库系统的,但是这并不代表不能对其它数据库系统实施类似的攻击。使用不同的方法,各种数据库都有可能遭殃。
      </para>
     </note>
+    <para>
+     <mediaobject>
+      <alt>关于 SQL 注入问题的工作实例</alt>
+      <imageobject>
+       <imagedata fileref="en/security/figures/xkcd-bobby-tables.png" format="PNG"/>
+      </imageobject>
+     </mediaobject>
+     Image courtesy of <link xlink:href="&url.xkcd;327">xkcd</link>
+    </para>
 
     <sect2 xml:id="security.database.avoiding">
      <title>预防措施</title>
@@ -297,9 +319,9 @@ $result = mssql_query($query);
       <listitem>
        <simpara>
         检查输入的数据是否具有所期望的数据格式。PHP
-        有很多可以用于检查输入的函数,从简单的<link
-        linkend="ref.var">变量函数</link>和<link
-        linkend="ref.ctype">字符类型函数</link>(比如
+        有很多可以用于检查输入的函数,从简单的
+        <link linkend="ref.var">变量函数</link> 和
+        <link linkend="ref.ctype">字符类型函数</link>(比如
         <function>is_numeric</function>,<function>ctype_digit</function>)到复杂的
         <link linkend="ref.pcre">Perl 兼容正则表达式函数</link>都可以完成这个工作。
        </simpara>
@@ -350,6 +372,7 @@ $query = sprintf("SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET %d
        </simpara>
       </listitem>
      </itemizedlist>
+
      <simpara>
       除此之外,在允许的情况下,使用代码或数据库系统保存查询日志也是一个好办法。显然,日志并不能防止任何攻击,但利用它可以跟踪到哪个程序曾经被尝试攻击过。日志本身没用,要查阅其中包含的信息才行。毕竟,更多的信息总比没有要好。
      </simpara>