存档

文章标签 ‘Android’

手机应用的信任关系

2010年10月25日 没有评论

前几天参加了支付和移动互联网峰会,写了一些想法。这几天还在思考一个问题:如何才能信任一个手机应用呢?

对于基于网页的应用,这个问题比较好解决。我们在浏览器里打开某网站地址,可以通过检查URL是否正确,对于https的地址,还可以查看安全证书。如果这些都没有问题,就可以确认访问到的网站是我们希望的,而不是李鬼。

对于应用程序,有数字签名来保证一个程序是某开发者发布且没有被修改过。当确认签名没有问题的时候,就可以放心使用了。

看看上面两种情况,为什么能信任一个以前没有接触过的网页或应用呢?我觉得这是信任的传递过程。对于网页应用,首先,我信任使用的浏览器,才确定浏览器展示给我的URL和安全证书是网页本身的;我信任安全证书签发机构,才信任证书的使用者。这是把对浏览器和证书签发机构的信任传递到网页上。对于应用程序,我信任操作系统,才确定展示给我的数字签名的确是应用本身的;我信任数字签名签发机构,才信签名的使用者。这是把对操作系统和数字签名签发机构的信任传递到应用上。

到了手机上,对于网页,没有什么差别,但对于应用来说,情况有所不同。

看看Android的情况。每个应用发布时都需要签名,但这个签名是应用开发者自己创建的签名,没有第三方机构签发。手机上的操作系统还是可以信任的,但操作系统并不能把应用的签名情况展示给用户。

单单对于一个应用本身,我无法确认是不是声称的开发者发布的。当我要找某银行的应用时,Google market上的应用都不一定可靠,因为任何人都可以发布一个声称是银行的应用。Google在发布环境基本没有审察,即使是钓鱼也会在Market上被用户看到。这条路无法建立信任,我通常会到银行的官方网站,通过其提供的链接来下载应用。这相当与把对网站的信任传递到应用上。

在iPhone上,情况好一些。因为app store有发布前的审察机制,肯定不能100%过滤,但会提高钓鱼者成本。对于银行、交易相关应用,还是小心一些为好,最好也通过官方网站链接访问。

应用内支付IAP (In-App Purchase),问题就更大了。信任链在应用这就已经断掉了,应用的身份无法信任,我怎么能信任这个应用展示给我的支付界面呢?看到Paypal、Alipay都在做这个工作,但就目前的情况来说,我不看好。对于钓鱼,恐怕都是事后处理,而不能在之前防范。有用户被钓鱼,自然不敢使用;有防范意识的用户,知道钓鱼程序无法识别的话,可能会拒绝所有程序。这样,这个市场随着一些用户被钓鱼和一些用户增强防范意识,会变得越来越小。

App store也有IAP,但使用的是自己的支付手段,钓鱼者最多得到用户的app store帐号或者让用户用这个帐号购买一些东西,但交易后如果用户发现,可以向app store申诉。这样,钓鱼者即使钓鱼成功也未必能有收益,买卖就不划算了。这个方式并不是建立信任链,而是通过控制支付达到的。

但第三方支付就不这么容易了。Alipay似乎可以在其界面输入银行帐号密码来直接从银行转帐。钓鱼这可以仿造支付界面,骗取银行信息。对Alipay来说,他的任何代码和服务器都没有参与这个行为,怎么能找他负责呢?银行也没有看到有这笔交易,除非用户在输入信息后立即发现问题,否则银行也无法发现。

即使Alipay使用了淘宝的收货后确认付款的机制,也是有问题的,原因仍然是在于对应用没有信任。不像网页上,操作都是在淘宝/支付宝的域名下完成,手机上的交易是在一个没有信任关系的应用里进行,我并不知道我的帐号信息发给alipay服务器的同时是否还被这个应用留了一份。不过,如果使用收货后确认付款的机制加上OTP (one time password),应该就会安全了,因为即使应用留了一份帐号信息,也是无效的。

总之,由于手机系统的原因,信任不能传递到应用,仅仅在手机应用本身的支付是不安全的,要做的话,需要在手机之外打些补丁。

分类: Android, iOS 标签: ,

手机支付的思考

2010年10月20日 没有评论

今天,听了支付宝支付和移动互联网峰会,会上介绍了支付宝的手机支付。会上提到的支付方式,是与Apple的IAP (In-App Purchase) 类似,在应用中通过调用支付宝的接口来实现支付,购买游戏中道具或关卡、以及应用中的某些功能。

演示这个支付方式的程序,是运行在Android平台的,但这是Google Android market明文禁止的。前些天我还听说有Android开发者因为在程序中使用了Paypal支付方式而被Google suspend了。这样说来,使用这种支付方式就不能在Google Android market上发布了。不过,要是在其他market发布,现在没听说哪个非Google的market能占绝对的市场份额,开发者就要忙于在各个market发布了。

在介绍过程中,我还想到另一个问题:如何防钓鱼。开始时我只是觉得或许会有人钓鱼,窃取用户资料。在会议结束后,恰好碰到一个阿里巴巴的人,和他讨论了这个问题,他也没说出什么好的解决办法,更多的是事后补救。在回来的路上,我又仔细想了想,这个问题影响将很大,不仅仅是被钓鱼者,也会使有防范意识的人不敢使用这种支付方式。

先来看看正常的支付过程:某个应用中,有需要付费的项目,用户点击后,进入到支付宝界面,用户在支付宝界面中输入用户帐号密码,成功后返回应用。

那么,钓鱼的应用也可以在界面上模仿这个过程,只不过不使用支付宝界面,而是用自己的界面模拟支付宝。在获取用户资料后,发给钓鱼服务器。

电脑上,可以通过安全控件防止监听键盘,通过检查url来防止把账户信息输入到不信任的服务器上。但对于手机用户来说,并不知道这个支付界面的到底是谁的,支付宝还是钓鱼程序,因为支付界面都是由一个未必通过认证的程序展示出来的。

某个界面,并没有url可以让用户检查。虽然有package的名字,但对用户不可见,并且这也是可以模仿的。

在支付界面显示预留信息,或者短信认证,也不是安全的办法。首先,要显示预留信息,就要求用户先登录,之后才能判断。这时即使发现问题,用户帐号也已经泄露了。另外,钓鱼程序可以通过夹在用户和支付宝之间,做一个代理来获取帐号信息,骗过用户。这里不存在电脑上MITM会遇到的证书错误问题。

其他防钓鱼的方法,我能想到的就是在程序之外验证,比如OTP (one time password),这肯定能保护帐号,但需要额外设备,有成本。

这个认证是一个双向认证,用户要认证服务器是正确的服务器,而服务器也要认证用户身份。在电脑上,这个过程有CA机构签发证书保证,但手机上缺少了这个角色,就无法认证服务提供者。OTP可以说是另一个认证服务器的方式,来保证服务器的身份。

或者,如果确认程序本身是没有恶意的,也可以。但目前的Google market没有审核机制,这个无法保证。Apple的app store也有IAP方式,但因为程序是要经过审核的,钓鱼程序会被审核过滤,也很难有鱼上钩。

Android程序虽然有签名,但这是开发者自己建立的签名,并不能说明身份。不像ssl证书,是由可信机构签发。

总之,问题的根本在于要求我输入帐号信息的界面不能证明自己是支付界面,只能通过程序之外来证明,增加了认证成本。但目前没有看到这方面的支持,在解决这个疑问之前,没有防范意识的用户有安全风险,有防范意识的用户也无法识别真伪。

不知道Google禁止第三方支付是不是也基于这个原因,或许是为了保证用户安全。

分类: Android 标签: ,

iOS学习笔记——与Android比较

2010年9月8日 没有评论

用了一段时间iTouch和G1,说说比较这两个系统。

1. 用户感受上iOS比Android流畅,或许是G1是Android手机里配置比较低的原因,但查了一下,iTouch的配置也不是很高。流畅主要是体现在切换屏幕,滚动等操作上,很及时响应操作,效果也没有停滞的感觉。

2. 开发环境中,感觉Interface builder比Eclipse中的界面编辑器好用多了。用Eclipse,我基本上都是手工改xml,很少用所谓的图形化编辑器的,我有两点受不了:一是界面编辑器生成的xml代码,格式相当混乱,不换行,甚至把几个控件放在同一行;二是在里面托拽一个控件,有时会产生不可预知的结果,控件相对位置并不是所见即所得,设计与运行有差异。

3. 从app看,iOS普遍比Android的应用大。iOS上app动辄几十兆,有的甚至几百兆,而Android上app大部分还在几百K到几兆。这或许与两个系统的应用机制有关。在下载方面:iOS的app store可以在手机和电脑上下载,而较大的应用限制在只能通过电脑下载。在这样的方式下,文件大小不是个大问题。而Android的market,只能通过手机内置的程序下载,过大的程序下载起来就很不方便。在存储方面:iOS的存储内置,8G/16G/32G/64G,都可以作为存储空间。Android的应用在2.2之前,只能存在机内,目前主流机型都是几百兆,这里还要扣除系统占用的部分,之后剩余就更少了。2.2之后,虽然引入了存在SD卡上的方式,但有限制,某些应用仍然不能存在SD卡上,比如需要开机启动的程序。

应用的大小并不直接说明问题,但可以有更大的应用,会使开发者有更大发挥的空间。对于游戏和资料类的应用来说尤其如此。游戏可以增加更精美的画面,资料类应用可以有更丰富内容,甚至加入声音、视频。

4. 界面上,iOS更加漂亮,统一。Android上一水是灰色的按钮,有点像Windows 3.1。Apple有用户界面的指导,而我没有看到Android上有类似的文件,这个指导使不同应用遵循同样的标准设计,用户的学习成本大大降低了。而Android上的应用则是百花齐放,需要用户适应不同的程序。

以上是最近一段时间对iOS和Android的想法,似乎都是iOS的有点和Android的不足,或许还是因为做Android时间长些,更加了解。

不知道Android 3.0能是一个什么样子,我最期望的有三点:一是更好的界面,要让普通用户觉得漂亮,仅仅是靠内秀吸引geek是不会有大发展的;二是如何统一机内flash和SD卡,以及调整应用下载方式,使上百兆大应用成为可能,market里都是几兆的工具类应用不是健全的market;三是对开发者的后台再完善些,现在的后台做的有些简陋,完全不是Google的风格,另外国内也无法开通应用收费功能。

分类: Android, iOS 标签: ,

G字辈,我晕啊

2010年7月14日 1 条评论

T-Mobile在发售HTC Dream把机器叫做T-Mobile G1,这款机器是第一款Android手机,也是G字辈的大师兄。之后HTC的Android手机,不管叫什么,都会被起一个G什么的艺名。刚刚看到,现在似乎已经排到G8了。

这些名字似乎只有中文圈里这么叫,Google了一下,没有找到相关的英文内容。对这个G字辈的排行,我总是记不住谁对应谁。除了G1真有这个名字之外,其他的和本身的名称一点关系都没有,只能死记硬背。不是天天折腾手机,谁有这个时间精力背这个呢。尤其是Nexus One,嫌名字长,叫N1不是挺好的吗,为什么还要G什么的?

鉴于到处都是G字辈的,为了节省以后查资料的时间,我还是把G字辈的简历放在这里:

G1

姓名: HTC Dream / T-Mobile G1 / Era G1

出生日期: 2008/10/22

CPU: 528M

闪存: 256MB

内存: 192MB

屏幕: 320×480, 3.2 in, 65536 color, 180 ppi, 电容屏

摄像头: 3.2m, 自动对焦

无线: 802.11b/g, Bluetooth 2.0+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, UMTS 1700 2100 MHz, HSDPA/HSUPA 7.2/2 Mbit/s

G2

姓名: HTC Magic / T-Mobile myTouch 3G / docomo HT-03A

出生日期: 2009/04/27

CPU: 528M

闪存: 512MB

内存: 192/288MB

屏幕: 320×480, 3.2 in, 65536 color, 180 ppi, 电容屏

摄像头: 3.2m, 自动对焦

无线: 802.11b/g, Bluetooth 2.0+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, UMTS 900 1700 2100 MHz, HSDPA/HSUPA 7.2/2 Mbit/s

G3

姓名: HTC Hero / T-Mobile G2 Touch / Era G2 Touch

出生日期: 2009/06/24

CPU: 528M

闪存: 512MB

内存: 288MB

屏幕: 320×480, 3.2 in, 65536 color, 180 ppi, 电容屏

摄像头: 5.0m, 自动对焦

无线: 802.11b/g, Bluetooth 2.0+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, UMTS 900 2100 / 850 1900 MHz

G4

姓名: HTC Tattoo / HTC Click

出生日期: 2009/10/19

CPU: 528M

闪存: 512MB

内存: 256MB

屏幕: 240×320, 2.8 in, TFT

摄像头: 3.2m,定焦

无线: 802.11b/g, Bluetooth 2.0+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, HSPA/WCDMA 900 2100 MHz

G5

姓名: Nexus One / HTC Dragon / HTC Passion

出生日期: 2010/01/05

CPU: 1G

闪存: 512MB

内存: 512MB

屏幕: 480×800, 3.7 in, 24-bit AMOLED, 254 ppi

摄像头: 5.0m, 自动对焦, LED flash, video 720×480 @ 20 fps

无线: 802.11b/g/n, Bluetooth 2.1+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, UMTS 900 1700 2100 MHz, HSDPA/HSUPA 850 1900 2100

G6

姓名: HTC Legend / HTC Dragon / HTC Passion

出生日期: 2010/03/16

CPU: 600M

闪存: 512MB

内存: 384MB

屏幕: 320×480, 3.2 in, AMOLED

摄像头: 5.0m, 自动对焦

无线: 802.11b/g, Bluetooth 2.1+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, HSPA/WCDMA 900 2100 MHz

G7

姓名: HTC Desire

出生日期: 2010/03/26

CPU: 1G

闪存: 512MB

内存: 576MB

屏幕: 480×800, 3.7 in, AMOLED

摄像头: 5.0m, 自动对焦, LED flash

无线: 802.11b/g, Bluetooth 2.1+EDR, A-GPS, GSM 850 900 1800 1900 MHz, GPRS/EDGE, HSPA/WCDMA 900 2100 MHz

G8(有不同说法)

姓名: HTC Incredible

出生日期: 2010/04/29

CPU: 1G

闪存: 1G

内存: 512MB

屏幕: 480×800, 3.7 in, AMOLED, 252 ppi

摄像头: 8.0m, 自动对焦, LED flash

无线: 802.11b/g, Bluetooth 2.1+EDR, A-GPS, FM, CDMA2000/EV-DO Rev. A

分类: Android 标签: ,

折腾记录:Android上增加img.ly上传

2010年5月6日 没有评论

好久没有更新了,一直在做我的Android程序,但目前看来一时半会儿做不完,还是调整一下节奏,也把做的过程中遇到的问题记录一下。

昨天,打算把我的程序中加入拍照并上传到img.ly的功能,遇到了一串问题。

问题一:Android下调用拍照Activity

通过MediaStore.ACTION_IMAGE_CAPTURE这个Intent可以使用系统提供的拍照功能,但用了之后,发现拍摄的照片相当小,即使设了MediaStore.EXTRA_OUTPUT,也是没有作用。

Google之后,发现这是个已知的问题:http://code.google.com/p/android/issues/detail?id=1480,唉,郁闷。

看了几个其他Android上支持拍照的程序,他们也只能拍小图片。算了,小就小吧,还省流量呢,哈哈

问题二:上传代码

查阅img.ly的API文档,真是简单,只有一页。里面说格式为multipart/form-data,要求三项:media, username, password。

找遍了Android文档,没有发现支持multipart/form-data的Http相关函数。Google之,org.apache.http新版本中包含了对Multipart的支持,但Android中带的org.apache.http没有。一个Android Team的回答

Note that this has been removed because it was removed from the Apache
HttpClient library that we’re bundling. What you want to do is get
Mime4j ( http://james.apache.org/mime4j/index.html ) and HttpMime
( http://hc.apache.org/httpcomponents-client/httpmime/index.html ) and
include these libraries in your Android project. From there, the usage
of multipart requests is pretty intuitive.

按照他的说法,下载了mime4j和httpmime,终于可以支持multipart/form-data了。

问题三:HTTP Error 411 Length required

按照img.ly的API,在post中加入了media, username, password,运行。得到一个Exception,因为img.ly返回HTTP Error 411 Length required。

抓包,看到发出的http请求里,的却没有Content-length。尝试直接通过代码加入Content-length,未果,还触发异常。

Google之,找到了原因:我针对media这个字段,使用的是InputStreamBody,这个Body的getContentLength()返回-1,造成不能计算总的长度,所以http header里没有Content-length。

这个帖子里给出了一个解决方法,自己写了一个ByteBody。这个代码是08年的,可能是针对以前的版本,我照猫画虎,做了一个:

import java.io.IOException;
import java.io.OutputStream;

import org.apache.http.entity.mime.MIME;
import org.apache.http.entity.mime.content.AbstractContentBody;

public class ByteBody extends AbstractContentBody {
	private final byte[] mContent;

	public ByteBody(final byte[] content, final String mimeType) {
		super(mimeType);
		if (content==null) {
			throw new IllegalArgumentException("File may not be null");
		}
		this.mContent = content;
	}

	@Override
	public void writeTo(OutputStream out) throws IOException {
		if (out == null) {
            throw new IllegalArgumentException("Output stream may not be null");
        }
        try {
            out.write(mContent, 0, mContent.length);
            out.flush();
        } finally {
        }
	}

	@Override
	public String getFilename() {
		return("bytearray");
	}

	@Override
	public String getCharset() {
		return null;
	}

	@Override
	public long getContentLength() {
		return mContent.length;
	}

	@Override
	public String getTransferEncoding() {
		return MIME.ENC_BINARY;
	}

}

运行,终于HTTP 411不出现了,但又来了新的问题……

问题四:Invalid twitter username or password

这个提示很奇怪,明明我提供的是正常的。联想到在使用MultipartEntity之前,我曾经用直接写代码的方式实现post请求,没有出现这个问题,是不是MultipartEntity发送的格式img.ly不接受,造成不能识别username/password。

MultipartEntiry的发送格式是:

Content-Disposition: form-data; name=”username”
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

suzginfo

找了一个可以上传到img.ly的程序,抓包看它的发送格式 —— 它竟然用https发送,看不到发送内容!

不过,我又发现,它的logcat里,有发送内容,太好了

Content-Disposition: form-data; name=”username”

suzginfo

和我的差别是没有Content-Type和Content-Transfer-Encoding。

看文档和源文件,MultipartEntity是有两个模式,STRICT和BROWSER_COMPATIBLE,缺省的是STRICT。在STRICT下,会发送Content-Type和Content-Transfer-Encoding。而BROWSER_COMPATIBLE不会发送。

换成了BROWSER_COMPATIBLE模式,Invalid twitter username or password消失了,错误变成了Invalid image type。看来对于media字段来说,是需要Content-Type的。这个在分析另一个程序的logcat中,也看到了它发送Content-Type和Content-Transfer-Encoding。

这个就麻烦了,我需要STRICT和BROWSER_COMPATIBLE的组合模式,对username和password不发送Content-Type,而media发送。

没办法,重写MultipartEntity和HttpMultipart。在HttpMultipart.doWriteTo里,如果Content-Type是text/plain,就跳过,直接发送内容。

修改后,终于可以上传图片了,内牛满面啊~

分类: Android 标签: , ,