附录C. 加密

作为一本相关安全方面的书,通常加密是需要提及的话题。我之所以在本书的主体部分忽略了加密问题,是因为它的用途是狭窄的,而开发者应从大处着眼来考虑安全问题。过分依赖于加密常常会混淆问题的根源。尽管加密本身是有效的,但是进行加密并不会神奇地提高一个应用的安全性。

一个PHP开发人员应主要熟悉以下的加密方式:

l        对称加密

l        非对称加密(公钥)

l        Hash函数(信息摘要)

l        信息验证码

本附录主要关注于使用mcrypt扩展的对称加密算法。你需要参考的资料如下:

实用加密技术(Applied Cryptography), by Bruce Schneier (Wiley)

http://www.schneier.com/blog/

http://wikipedia.org/wiki/Cryptography

http://phpsec.org/articles/2005/password-hashing.html

http://pear.php.net/package/Crypt_HMAC

http://pear.php.net/package/Crypt_RSA

C.1. 密码的存储

当你在数据库内存储的密码时,永远不要以明码方式存入,而是应该存储密码的hash值并同时使用附加字串:

<?php

/* $password contains the password. */

$salt = 'SHIFLETT';

$password_hash = md5($salt . md5($password . $salt));

/* Store password hash. */

?>

当你需要确认一个密码是否正确时,以同样的方式计算出hash值并比较异同:

<?php

$salt = 'SHIFLETT';

$password_hash = md5($salt . md5($_POST['password'] . $salt));

/* Compare password hashes. */

?>

如果hash值完全相同,你就有理由认为密码也是相同的。

如果使用了这个技巧,是不可能告诉用户他们的密码是什么的。当用户忘记密码时,你只能让他录入一个新密码并重新计算hash值存入数据库。当然,你需要非常小心地对用户进行身份确认——密码提醒机制是易受频繁攻击的目标,同时也是经常出现安全漏洞的源头。

C.2. 使用mcrypt

PHP的标准加密扩展是mcrypt,它支持很多不同的加密算法。你可以通过mcrypt_list_algorithms( )函数来查看你的平台上支持的算法列表:

<?php

echo '<pre>' . print_r(mcrypt_list_algorithms(), TRUE) . '</pre>';

?>

加密和解密分别由mcrypt_encrypt( ) 及 mcrypt_decrypt( )函数来实现。这两个函数都有5个参数,第一个参数是用于指定使用的算法:

<?php

mcrypt_encrypt($algorithm,

$key,

$cleartext,

$mode,

$iv);

mcrypt_decrypt($algorithm,

$key,

$ciphertext,

$mode,

$iv);

?>

其中的加密键(第二个参数)是非常敏感的数据,因此你要确保把它存放在安全的地方。可以用第八章中保护数据库权限的方法来保护加密键。如果经济条件允许的话,硬件加密键是最好的选择,它提供了超级强大的安全性。

函数有多种模式可供选择,你可以使用mcrypt_list_modes( )来列出所有支持的模式:

<?php

echo '<pre>' . print_r(mcrypt_list_modes(), TRUE) . '</pre>';

?>

第五个参数($iv)为初始化向量,可以使用mcrypt_create_iv( )函数建立。

下面的示例类提供了基本的加密解密方法:

class crypt

{

private $algorithm;

private $mode;

private $random_source;

public $cleartext;

public $ciphertext;

public $iv;

public function __construct($algorithm = MCRYPT_BLOWFISH,

$mode = MCRYPT_MODE_CBC,

$random_source = MCRYPT_DEV_URANDOM)

{

$this->algorithm = $algorithm;

$this->mode = $mode;

$this->random_source = $random_source;

}

public function generate_iv()

{

$this->iv = mcrypt_create_iv(mcrypt_get_iv_size($this->algorithm,

$this->mode), $this->random_source);

}

public function encrypt()

{

$this->ciphertext = mcrypt_encrypt($this->algorithm,

$_SERVER['CRYPT_KEY'], $this->cleartext, $this->mode, $this->iv);

}

public function decrypt()

{

$this->cleartext = mcrypt_decrypt($this->algorithm,

$_SERVER['CRYPT_KEY'], $this->ciphertext, $this->mode, $this->iv);

}

}

?>

上面的类会在其它示例中使用,下面是它的使用方法示例:

<?php

$crypt = new crypt();

$crypt->cleartext = 'This is a string';

$crypt->generate_iv();

$crypt->encrypt();

$ciphertext = base64_encode($crypt->ciphertext);

$iv = base64_encode($crypt->iv);

unset($crypt);

/* Store $ciphertext and $iv (initialization vector). */

$ciphertext = base64_decode($ciphertext);

$iv = base64_decode($iv);

$crypt = new crypt();

$crypt->iv = $iv;

$crypt->ciphertext = $ciphertext;

$crypt->decrypt();

$cleartext = $crypt->cleartext;

?>

小提示

本扩展要求你在编译PHP时使用-mcrypt标识。安装指南及要求详见http://php.net/mcrypt。

C.3. 信用卡号的保存

我常常被问到如何安全地保存信用卡号。我的总是会首先询问他们是否确实有必要保存信用卡号。毕竟不管具体是如何操作的,引入不必要的风险是不明智的。同时国家法律还有关于信用卡信息处理方面的规定,我还时刻小心地提醒我并不是一个法律专家。

本书中我并不会专门讨论信用卡处理的方法,而是会说明如何保存加密信息到数据库及在读取时解密。该流程会导致系统性能的下降,但是确实提供了一层保护措施。其主要优点是如果数据库内容泄密暴露出的只是加密信息,但是前提是加密键是安全的。因此,加密键与加密的实现方法本身同样重要。

保存加密数据到数据的过程是,首先加密数据,然后通过初始向量与明文建立密文来保存到数据库。由于密文是二进制字符串,还需要通过base64_encode( )转换成普通文本字符串以保证二进制编码的安全存储。

<?php

$crypt = new crypt();

$crypt->cleartext = '1234567890123456';

$crypt->generate_iv();

$crypt->encrypt();

$ciphertext = $crypt->ciphertext;

$iv = $crypt->iv;

$string = base64_encode($iv . $ciphertext);

?>

保存该字串至数据库。在读取时,则是上面流程的逆处理:

<?php

$string = base64_decode($string);

$iv_size = mcrypt_get_iv_size($algorithm, $mode);

$ciphertext = substr($string, $iv_size);

$iv = substr($string, 0, $iv_size);

$crypt = new crypt();

$crypt->iv = $iv;

$crypt->ciphertext = $ciphertext;

$crypt->decrypt();

$cleartext =  $crypt->cleartext;

?>

本实现方法假定加密算法与模式不变。如果它们是不定的话,你还要保存它们以用于解密数据。加密键是唯一需要保密的数据。

C.4. 加密会话数据

如果你的数据库存在安全问题,或者部分保存在会话中的数据是敏感的,你可能希望加密会话数据。除非很有必要,一般我不推荐这样做,但是如果你觉得在你的情形下需要这样做的话,本节提供了一个实现方法的示例。

这个方案十分简单。实际上,在第八章中,已经说明了如何通过调用session_set_save_handler( )来执行你自己的会话机制。通过对保存和读取数据的函数的少量调整,你就能加密存入数据库的数据及在读取时解密数据:

<?php

function _read($id)

{

global $_sess_db;

$algorithm = MCRYPT_BLOWFISH;

$mode = MCRYPT_MODE_CBC;

$id = mysql_real_escape_string($id);

$sql = "SELECT data

FROM   sessions

WHERE  id = '$id'";

if ($result = mysql_query($sql, $_sess_db))

{

$record = mysql_fetch_assoc($result);

$data = base64_decode($record['data']);

$iv_size = mcrypt_get_iv_size($algorithm, $mode);

$ciphertext = substr($data, $iv_size);

$iv = substr($data, 0, $iv_size);

$crypt = new crypt();

$crypt->iv = $iv;

$crypt->ciphertext = $ciphertext;

$crypt->decrypt();

return $crypt->cleartext;

}

return '';

}

function _write($id, $data)

{

global $_sess_db;

$access = time();

$crypt = new crypt();

$crypt->cleartext = $data;

$crypt->generate_iv();

$crypt->encrypt();

$ciphertext = $crypt->ciphertext;

$iv = $crypt->iv;

$data = base64_encode($iv . $ciphertext);

$id = mysql_real_escape_string($id);

$access = mysql_real_escape_string($access);

$data = mysql_real_escape_string($data);

$sql = "REPLACE

INTO    sessions

VALUES  ('$id', '$access', '$data')";

return mysql_query($sql, $_sess_db);

}

[新闻]NHibernate 2.0.0.Beta1发布了
文章来源:http://www.cnblogs.com/czh-liyu/archive/2008/04/02/1133998.html

转载于:https://www.cnblogs.com/xfliu/archive/2008/07/01/1233385.html

[导入]php 安全基础 附录C. 加密相关推荐

  1. [导入]php 安全基础 附录B. 函数

    附录B. 函数 在我写作本书的时候,http://php.net/quickref.php列出了共3917个函数,其中包括一些类似函数的语法结构,在此我不准备把它们从函数中区分开来,而是把它作为函数看 ...

  2. Linux 基础命令讲解--加密解密

    Linux 基础命令讲解--加密解密 加密文件: 1.MD5 echo -n "string" | openssl md5   #加密字符串 openssl md5 -in tes ...

  3. 密码学基础以及完整加密通讯过程解析

    密码学基础以及完整加密通讯过程解析 前言 一.密码学相关基本概念 二.对称加密 三.非对称加密 四.杂凑算法 五.完整加密通讯过程 前言 密码学是研究如何隐密地传递信息的学科. 密码是通信双方按约定的 ...

  4. 【Python 实战基础】如何加密手机号

    目录 一.实战场景 二.主要知识点 文件读写 基础语法 字符串处理 正则表达式 三.菜鸟实战 1.创建 python 文件 2.运行结果 一.实战场景 实战场景:如何加密手机号 二.主要知识点 文件读 ...

  5. pfx导入后仍然打不开加密文件_天正CAD图纸加密和解密方法

    CAD作图的时候如果要发给别人,但又怕别人任意修改,或者怕别人盗取你的图纸时,图纸加密就很有必要了 方法一:CAD加密 打开你需要加密的图纸,输入"OP"打开选项窗口,点击&quo ...

  6. GreenDao3.0 使用(包括导入,具体方法,基本使用,加密,数据库升级等)

    关于GreenDao greenDao是一个将对象映射到SQLite数据库中的轻量且快速的ORM解决方案.关于greenDAO的概念可以看官网greenDAO greenDAO 优势 1.一个精简的库 ...

  7. 【linux】循序渐进学运维-基础篇-grub加密技术

    文章目录 前言 实验 环境: 实验步骤 1. 对grub进行加密 2. 重启测试加密效果 总结 高胜寒的碎碎念 大家好,我是高胜寒,本文是Linux运维-循序渐进学运维-基础篇的第55篇文章. 前言 ...

  8. 导入excel(基础表+多表头(二级表头,三级表头)-封装组件实现导入xslx)推荐使用

    一级表头:↓ 二级表头↓ 三级表头↓ 思路:封装一个导入的组件,然后全局引用,可以导入基础表,二级表头,三级表头. 封装的组件的作用:接收用户上传的文件 xslx插件的任务:把用户上传的文件转换成 后 ...

  9. 【linux】循序渐进学运维-基础篇-磁盘加密解密技术

    大家好,我是高胜寒,本文是Linux运维-循序渐进学运维-基础篇的第57篇文章. 文章目录 前言: 实验步骤 1. 对磁盘进行分区格式化 2. 对新建的分区进行加密 3. 挂载测试 a) 加密情况下无 ...

最新文章

  1. Java操作memcache
  2. 升级 ubuntu_Ubuntu 19.04 已经到期!现有用户必须升级到 Ubuntu 19.10
  3. 三菱socket通信实例_三菱QUnCPU内置以太网Socket通信(TCP篇)
  4. 如和用Python获取今日头条上面三千美女图,且看教程
  5. 网络工程师英语系列2(CISCO IP Telephony)
  6. MIT6.006Lec03:插入排序,归并排序,递归树
  7. centos6.4 安装wireless驱动
  8. jQuery 鼠标事件
  9. iOS TableView性能优化
  10. 2020苏州大学计算机考研经验总结博
  11. 1976国际标准大气模型_Matlab
  12. 在VC++中的MFC利用一个dialoge对话框中按钮调用另一个dialoge对话框
  13. JAVA-计算两篇文章的相似度
  14. 2022年CPU天梯图(7月更新)
  15. 中国的阿甘——我很蠢,但我很幸运
  16. SyntaxError: Invalid regular expression: invalid group specifier name
  17. 杭州再发力!余杭又添一区块链产业园,携手巴比特欲打造创新应用示范区
  18. 命令解压aar、文件压缩成aar图文详解
  19. 如何打造一个可躺赚的网盘项目,每天只需要2小时
  20. openFOAM动量方程中张量的处理

热门文章

  1. matlab练习程序(最小二乘多项式拟合)
  2. 消息队列RabbitMQ基础知识详解
  3. ORACLE内存结构简介
  4. 【数理知识】方程一阶二阶及常用词语含义
  5. 第六章 6.1 6.2 无限脉冲响应滤波器
  6. RK2908开机时间分析及优化
  7. Matlab篇(二)MATLAB中addpath的用法 (转)
  8. 并行计算及GPU简介
  9. void *变量用法
  10. STM32的ISP升级详解