概述
|
移动应用开发中,往往有跨进程通信的需求,方便地实现程序间的数据共享。
Android
提供了多种
IPC
通信的方式,给开发人员带来了便利,但如果选择或使用不当,就有可能发生各种各样的风险。
|
安全准则
|
A.
应用程序间的数据共享尽量优先采用
content provider
,尽量不要用带全局读写属性的
IPC
文件进行进程间通信(比如全局读写的
SharedPreferences
)。
B.
如果应用中的
content provider
、
Broadcast Receivers
、
Activities
和
Services
不需要被其它应用程序访问,应在
android manifest
文件中显式声明
android:exported=”false”
。
C.
如果组件需要被其它应用程序访问,应使用
permission
标签设置权限;如果只是在同一开发者开发的程序之间进行
IPC
,优先考虑使用
signature
级别的
permission
;
D.
content provider
支持对指定的
Uri
分别设置读写权限,建议只开放能完成任务的最小权限。
E.
使用
content provider
提供外部应用程序进行数据库存取时应使用带占位符的参数化查询防
SQL
注入。
F.
不要使用基于
socket
的
IPC
通信方式。
|
详细描述
|
A.
在
android manifest
文件中将
permission
的属性
android:protectionLevel
设置为
”signature”
,此时,具有相同签名的并且申请了相应权限的应用才可访问该组件,参考附录
4
。
B.
content provider
的独立读写权限设置方法可参考附录
5
。
C.
SQLiteDatabase
对象的部分内置方法是可以有效防
SQL
注入的,比如
query(),insert(),update
和
delete()
,另外,
正确地
使用
rawQuery()
也可以防止
SQL
注入,而
execSQL()
方法建议避免使用,如何正确的使用这些方法和相关错误案例请参考附录
3
。
|
备注
|
A.
当使用基于
socket
的
IPC
方式时,设备上的应用都可以访问该监听端口,最差的情况是端口完全对外开放监听,相当于任何应用都可以通过网络跟该端口进行通信。
B.
当一个组件定义了
intent-filter
,其
android:exported
的默认值为
true
,否则为
false
。
|
注:如果IE浏览器显示格式不正确,请使用chrome浏览器。
附录:
3
、SQLite防止SQL注入漏洞方案
11.1.1、使用SQLiteDatabase对象自带的防SQL注入的方法,比如query(),insert(),update和delete():
DatabaseHelper dbhelper =
new
DatabaseHelper(SqliteActivity.
this
,"sqliteDB");
SQLiteDatabase db = dbhelper.getReadableDatabase();
/*查询操作,userInputID和userInputName是用户可控制的输入数据 */
Cursor cur = db.query("user", new String[]{"id","name"}, "id=? and name=?", new String[]{userInputID,userInputName}, null, null, null);
/* 插入记录操作*/
ContentValues val =
new
ContentValues();
val.put("id", userInputID);
val.put("name", userInputName);
db.insert("user",
null
, val);
/*更新记录操作*/
ContentValues val =
new
ContentValues();
val.put("id", userInputName);
db.update("user", val, "id=?",
new
String[]{userInputID });
/*删除记录操作*/
db.delete("user", "id=? and name=?",
new
String[]{userInputID , userInputName });
11.1.2、正确地使用SQLiteDatabase对象的rawQuery()方法(仅以查询为例):
DatabaseHelper dbhelper =
new
DatabaseHelper(SqliteActivity.
this
,"sqliteDB");
SQLiteDatabase db = dbhelper.getReadableDatabase();
/* userInputID和userInputName是用户可控制的输入数据*/
String[] selectionArgs =
new
String[]{userInputID , userInputName };
String sql = "select * from user where id=? and name=?";//正确!此处绑定变量
Cursor curALL = db.rawQuery(
sql
, selectionArgs);
11.1.3、以下为
错误案例
!仅供参考:
DatabaseHelper dbhelper =
new
DatabaseHelper(SqliteActivity.
this
,"sqliteDB");
SQLiteDatabase db = dbhelper.getReadableDatabase();
/*案例1:错误地使用rawQuery(),未绑定参数*/
String
sql
= "select * from user where id='" + userInputID +"'";//错误!动态拼接,未绑定变量
Cursor curALL = db.rawQuery(sql, null);
/*案例2:使用execSQL()方法*/
String
sql
= "INSERT INTO user values('"+userInputID +"','"+userInputName +"')";//错误同上
db.execSQL(sql);
4
、使用signature级别的permission:
在应用的AndroidManifest.xml定义如下:
<!- 声明权限 ->
<permission
android:protectionLevel=
"
signature
"
android:name=
"com.hik.helloworld.activity"
/>
<activity
android:name=
"com.hik.helloworld.TestActivity"
android:label=
"@string/app_name"
android:exported=
"false"
<!- 为对应组件使用权限 ->
android:permission=
"com.hik.helloworld.activity"
>
</activity>
则只有相同数字签名的应用申请该权限后才可以访问该组件。
5
、contentProvider的独立读写权限设置
/* 只允许外部程序对特定Uri进行读操作时的样例设置 */
<
provider
android:name=".
MyContentProvider
"
android:authorities="
com.hik.contentprovider.MyContentProvider
"
android:exported=
"true"
android:multiprocess="true"
android:readPermission="
com.hik.contentprovider.MyContentProvider
.permission.read">
<path-permission android:pathPattern="/queryData/.*"
android:permission="
com.hik.contentprovider.MyContentProvider
.permission.read "/>
</
provider
>
/* 只允许外部程序对特定Uri进行写操作时的样例设置 */
<
provider
android:name=".
MyContentProvider
"
android:authorities="
com.hik.contentprovider.MyContentProvider
"
android:exported=
"true"
android:multiprocess="true"
android:writePermission="
com.hik.contentprovider.MyContentProvider
.permission.write">
<path-permission android:pathPattern="/updateData/.*"
android:permission="
com.hik.contentprovider.MyContentProvider
.permission.write "/>
</
provider
>