PHP中一些通用和易混淆技术点的最佳编程实践

我们使用的是哪个 PHP 版本?
带有 Suhosin-补丁的PHP 5.3.10-1ubuntu3.6, 安装于 Ubuntu 12.04 LTS.
PHP如同是网络世界的百年老龟。它的外壳上刻有一个丰富的,令人费解的,粗糙的历史。在一个共享主机的环境下,它的配置可能会限制你能做什么事情。

为了保留一丝明智,我们需要只专注于一个版本的PHP。截至2013年4月30,该版本是 带有Suhosin补丁的PHP5.3.10-1ubuntu3.6 。如果你使用apt-get从一个Ubuntu12.04 LTS服务器来安装PHP的话,你所得到的版本就是这个。换句话说,许多人在默认情况下已经很明智地使用了它。

您可能会发现本文这些解决方案能工作于不同或更旧版本的PHP。如果是这样的话,就要由你来研究在这些旧版本中的细微错误或安全问题的影响了。

保存密码
使用 phpass 库计算密码的哈希值进行比较。
用 phpass 0.3 进行的测试。

散列化是在把用户密码保存进数据库之前对其进行保护的标准方法。许多常见的散列算法,如MD5,乃至SHA1,用于存储密码都是不安全的,因为黑客可以使用这些散列算法轻松破解密码。

要散列化密码最安全的方法是使用bcrypt算法。开源的phpass 库用一个易于使用的类来提供这个功能。

例子:
01 <?php

02 // 包含phpass库

03 require_once('phpass-0.3/PasswordHash.php');

04  

05 // 初始化散列器为不可移植(这样更安全)

06 $hasher = new PasswordHash(8, false);

07  

08 // 计算密码哈希值。$hashedPassword 将会是一长为60个字符的字符串.

09 $hashedPassword = $hasher->HashPassword('my super cool password');

10  

11 // 你现在可以安全地保存$hashedPassword到数据库中!

12  

13 // 通过比较用户输入内容(产生的哈希值)和我们之前计算出的哈希值,来判断用户是否输入了正确的密码

14 $hasher->CheckPassword('the wrong password', $hashedPassword); // 返回假

15  

16 $hasher->CheckPassword('my super cool password', $hashedPassword); // 返回真

17 ?>

陷阱
很多来源会建议你在计算密码的哈希值之前先给密码加点“作料”。这是个好主意,phpass已经利用HashPassword() 函数中的一部分代码来为你给密码加了作料。 这就意味着你并不需要自己再亲自做这个了。
进一步阅读
phpass
Why hashing passwords with md5 or sha is unsafe
How to safely store a password

连接到并查询MySQL数据库
使用 PDO和它预定义的语句功能.
在PHP中有很多方法连接到一个MySQL数据库。 PDO (PHP Data Objects) 是其中最新最健壮的。对于许多不同类型的数据库,PDO都使用一致性的接口,采用面向对象的方式,并支持较新的数据库的提供的更多特性。

您应该使用PDO预定义语句的功能,以帮助防止SQL注入攻击。使用 bindValue() 函数确保你的SQL对于第一阶的SQL注入攻击是安全的(但这不是100%万无一失的,参考 进一步阅读 获得更详细说明)。在过去,这只能用一些“魔术引号”函数的复杂结合来实现。PDO使所有这些黏糊糊的东西变得不再必要了。

示例
01 <?php

02 try{

03     // Create a new connection.

04     // You'll probably want to replace hostname with localhost in the first parameter.

05     // The PDO options we pass do the following:

06     // \PDO::ATTR_ERRMODE enables exceptions for errors.  This is optional but can be handy.

07     // \PDO::ATTR_PERSISTENT disables persistent connections, which can cause concurrency issues in certain cases.  See "Gotchas".

08     // \PDO::MYSQL_ATTR_INIT_COMMAND alerts the connection that we'll be passing UTF-8 data.  This may not be required depending on your configuration, but it'll save you headaches down the road if you're trying to store Unicode strings in your database.  See "Gotchas".

09     $link = new \PDO(   'mysql:host=your-hostname;dbname=your-db',

10                         'your-username',

11                         'your-password',

12                         array(

13                             \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,

14                             \PDO::ATTR_PERSISTENT => false,

15                             \PDO::MYSQL_ATTR_INIT_COMMAND => 'set names utf8mb4'

16                         )

17                     );

18  

19     $handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');

20  

21     // PHP bug: if you don't specify PDO::PARAM_INT, PDO may enclose the argument in quotes.  This can mess up some MySQL queries that don't expect integers to be quoted.

22     // See: https://bugs.php.net/bug.php?id=44639

23     // If you're not sure whether the value you're passing is an integer, use the is_int() function.

24     $handle->bindValue(1, 100, PDO::PARAM_INT);

25     $handle->bindValue(2, 'Bilbo Baggins');

26     $handle->bindValue(3, 5, PDO::PARAM_INT);

27  

28     $handle->execute();

29  

30     // Using the fetchAll() method might be too resource-heavy if you're selecting a truly massive amount of rows.

31     // If that's the case, you can use the fetch() method and loop through each result row one by one.

32     // You can also return arrays and other things instead of objects.  See the PDO documentation for details.

33     $result = $handle->fetchAll(\PDO::FETCH_OBJ);

34  

35     foreach($result as $row){

36         print($row->Username);

37     }

38 }

39 catch(\PDOException $ex){

40     print($ex->getMessage());

41 }

42 ?>

陷阱
当绑定整型变量时,如果不传递PDO::PARAM_INT参数有事可能会导致PDO对数据加引号。这会 搞坏特定的MySQL查询。查看该bug报告。

未使用 `set names utf8mb4` 作为首个查询,可能会导致Unicode数据错误地存储进数据库,这依赖于你的配置。如果你 绝对有把握你的Unicode编码数据不会出问题,那你可以不管这个。

启用持久连接可能会导致怪异的并发相关的问题。这不是一个PHP的问题,而是一个应用层面 的问题。只要你仔细考虑了后果,持久连接一般会是安全的。查看Stack Overfilow这个问题。

即使你使用了 `set names utf8mb4` ,你也得确认实际的数据库表使用的是utf8mb4字符集!

可以在单个execute()调用中执行多条SQL语句。只需使用分号分隔语句,但注意这个bug,在该文档所针对的PHP版本中还没修复。

转载于:https://www.cnblogs.com/njgh/archive/2013/06/05/3118883.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值