W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
編寫(xiě):craftsmanBai - http://z1ng.net - 原文: http://developer.android.com/training/articles/security-gms-provider.html
安卓依靠security provider保障網(wǎng)絡(luò)通信安全。然而有時(shí)默認(rèn)的security provider存在安全漏洞。為了防止這些漏洞被利用,Google Play services 提供了一個(gè)自動(dòng)更新設(shè)備的security provider的方法來(lái)對(duì)抗已知的漏洞。通過(guò)調(diào)用Google Play services方法,可以確保你的應(yīng)用運(yùn)行在可以抵抗已知漏洞的設(shè)備上。
舉個(gè)例子,OpenSSL的漏洞(CVE-2014-0224)會(huì)導(dǎo)致中間人攻擊,在通信雙方不知情的情況下解密流量。Google Play services 5.0提供了一個(gè)補(bǔ)丁,但是必須確保應(yīng)用安裝了這個(gè)補(bǔ)丁。通過(guò)調(diào)用Google Play services方法,可以確保你的應(yīng)用運(yùn)行在可抵抗攻擊的安全設(shè)備上。
注意:更新設(shè)備的security provider不是更新android.net.SSLCertificateSocketFactory.比起使用這個(gè)類,我們更鼓勵(lì)應(yīng)用開(kāi)發(fā)者使用融入密碼學(xué)的高級(jí)方法。大多數(shù)應(yīng)用可以使用類似HttpsURLConnection,HttpClient,AndroidHttpClient這樣的API,而不必去設(shè)置TrustManager或者創(chuàng)建一個(gè)SSLCertificateSocketFactory。
使用providerinstaller類來(lái)更新設(shè)備的security provider。你可以通過(guò)調(diào)用該類的方法installIfNeeded()(或者 installifneededasync)來(lái)驗(yàn)證security provider是否為最新的(必要的話更新它)。
當(dāng)你調(diào)用installifneeded時(shí),providerinstaller會(huì)做以下事情:
如果設(shè)備的Provider成功更新(或已經(jīng)是最新的),該方法返回正常。
如果設(shè)備的Google Play services 庫(kù)已經(jīng)過(guò)時(shí)了,這個(gè)方法拋出googleplayservicesrepairableexception異常表明無(wú)法更新Provider。應(yīng)用程序可以捕獲這個(gè)異常并向用戶彈出合適的對(duì)話框提示更新Google Play services。
如果產(chǎn)生了不可恢復(fù)的錯(cuò)誤,該方法拋出googleplayservicesnotavailableexception表示它無(wú)法更新Provider。應(yīng)用程序可以捕獲異常并選擇合適的行動(dòng),如顯示標(biāo)準(zhǔn)問(wèn)題解決流程圖。
installifneededasync方法類似,但它不拋出異常,而是通過(guò)相應(yīng)的回調(diào)方法,以提示成功或失敗。
如果installifneeded需要安裝一個(gè)新的Provider,可能耗費(fèi)30-50毫秒(較新的設(shè)備)到350毫秒(舊設(shè)備)。如果security provider已經(jīng)是最新的,該方法需要的時(shí)間量可以忽略不計(jì)。為了避免影響用戶體驗(yàn):
線程加載后立即在后臺(tái)網(wǎng)絡(luò)線程中調(diào)用installifneeded,而不是等待線程嘗試使用網(wǎng)絡(luò)。(多次調(diào)用該方法沒(méi)有害處,如果安全提供程序不需要更新它會(huì)立即返回。)
如果用戶體驗(yàn)會(huì)受線程阻塞的影響——比如從UI線程中調(diào)用,那么使用installifneededasync()調(diào)用該方法的異步版本。(當(dāng)然,如果你要這樣做,在嘗試任何安全通信之前必須等待操作完成。providerinstaller調(diào)用監(jiān)聽(tīng)者的onproviderinstalled()方法發(fā)出成功信號(hào)。
警告:如果providerinstaller無(wú)法安裝更新Provider,您的設(shè)備security provider會(huì)容易受到已知漏洞的攻擊。你的程序等同于所有HTTP通信未被加密。 一旦Provider更新,所有安全API(包括SSL API)的調(diào)用會(huì)經(jīng)過(guò)它(但這并不適用于android.net.sslcertificatesocketfactory,面對(duì)cve-2014-0224這種漏洞仍然是脆弱的)。
修補(bǔ)security provider最簡(jiǎn)單的方法就是調(diào)用同步方法installIfNeeded().如果用戶體驗(yàn)不會(huì)被線程阻塞影響的話,這種方法很合適。
舉個(gè)例子,這里有一個(gè)sync adapter會(huì)更新security provider。由于它運(yùn)行在后臺(tái),因此在等待security provider更新的時(shí)候線程阻塞是可以的。sync adapter調(diào)用installifneeded()更新security provider。如果返回正常,sync adapter可以確保security provider是最新的。如果返回異常,sync adapter可以采取適當(dāng)?shù)男袆?dòng)(如提示用戶更新Google Play services)。
/**
* Sample sync adapter using {@link ProviderInstaller}.
*/
public class SyncAdapter extends AbstractThreadedSyncAdapter {
...
// This is called each time a sync is attempted; this is okay, since the
// overhead is negligible if the security provider is up-to-date.
@Override
public void onPerformSync(Account account, Bundle extras, String authority,
ContentProviderClient provider, SyncResult syncResult) {
try {
ProviderInstaller.installIfNeeded(getContext());
} catch (GooglePlayServicesRepairableException e) {
// Indicates that Google Play services is out of date, disabled, etc.
// Prompt the user to install/update/enable Google Play services.
GooglePlayServicesUtil.showErrorNotification(
e.getConnectionStatusCode(), getContext());
// Notify the SyncManager that a soft error occurred.
syncResult.stats.numIOExceptions++;
return;
} catch (GooglePlayServicesNotAvailableException e) {
// Indicates a non-recoverable error; the ProviderInstaller is not able
// to install an up-to-date Provider.
// Notify the SyncManager that a hard error occurred.
syncResult.stats.numAuthExceptions++;
return;
}
// If this is reached, you know that the provider was already up-to-date,
// or was successfully updated.
}
}
更新security provider可能耗費(fèi)350毫秒(舊設(shè)備)。如果在一個(gè)會(huì)直接影響用戶體驗(yàn)的線程中更新,如UI線程,那么你不會(huì)希望進(jìn)行同步更新,因?yàn)檫@可能導(dǎo)致應(yīng)用程序或設(shè)備凍結(jié)直到操作完成。因此你應(yīng)該使用異步方法installifneededasync()。方法通過(guò)調(diào)用回調(diào)函數(shù)來(lái)反饋其成功或失敗。 例如,下面是一些關(guān)于更新security provider在UI線程中的活動(dòng)的代碼。調(diào)用installifneededasync()來(lái)更新security provider,并指定自己為監(jiān)聽(tīng)器接收成功或失敗的通知。如果security provider是最新的或更新成功,會(huì)調(diào)用onproviderinstalled()方法,并且知道通信是安全的。如果security provider無(wú)法更新,會(huì)調(diào)用onproviderinstallfailed()方法,并采取適當(dāng)?shù)男袆?dòng)(如提示用戶更新Google Play services)
/**
* Sample activity using {@link ProviderInstaller}.
*/
public class MainActivity extends Activity
implements ProviderInstaller.ProviderInstallListener {
private static final int ERROR_DIALOG_REQUEST_CODE = 1;
private boolean mRetryProviderInstall;
//Update the security provider when the activity is created.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ProviderInstaller.installIfNeededAsync(this, this);
}
/**
* This method is only called if the provider is successfully updated
* (or is already up-to-date).
*/
@Override
protected void onProviderInstalled() {
// Provider is up-to-date, app can make secure network calls.
}
/**
* This method is called if updating fails; the error code indicates
* whether the error is recoverable.
*/
@Override
protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
if (GooglePlayServicesUtil.isUserRecoverableError(errorCode)) {
// Recoverable error. Show a dialog prompting the user to
// install/update/enable Google Play services.
GooglePlayServicesUtil.showErrorDialogFragment(
errorCode,
this,
ERROR_DIALOG_REQUEST_CODE,
new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// The user chose not to take the recovery action
onProviderInstallerNotAvailable();
}
});
} else {
// Google Play services is not available.
onProviderInstallerNotAvailable();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ERROR_DIALOG_REQUEST_CODE) {
// Adding a fragment via GooglePlayServicesUtil.showErrorDialogFragment
// before the instance state is restored throws an error. So instead,
// set a flag here, which will cause the fragment to delay until
// onPostResume.
mRetryProviderInstall = true;
}
}
/**
* On resume, check to see if we flagged that we need to reinstall the
* provider.
*/
@Override
protected void onPostResume() {
super.onPostResult();
if (mRetryProviderInstall) {
// We can now safely retry installation.
ProviderInstall.installIfNeededAsync(this, this);
}
mRetryProviderInstall = false;
}
private void onProviderInstallerNotAvailable() {
// This is reached if the provider cannot be updated for some reason.
// App should consider all HTTP communication to be vulnerable, and take
// appropriate action.
}
}
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: