封裝是要劃定清楚的界限。在網頁瀏覽器中,這可能意味著確保您的行動程式碼不會被其他行動程式碼濫用。在伺服器上,這可能意味著區分經過驗證的資料與未經驗證的資料、區分一個使用者的資料與另一個使用者的資料,或區分允許使用者查看的資料與不允許查看的資料。
script-src
、img-src
、object-src
、style_src
、font-src
、media-src
、frame-src
、connect-src
。這 8 個指令都將一個來源清單做為值,指定網站可存取的網域,以使用該指令所涵蓋的功能。開發人員可使用萬用字元 *
來指示所有或部分來源。其他來源清單關鍵字 (例如 'unsafe-inline'
和 'unsafe-eval'
) 提供更精細的方式來控制 script 執行,但這些是潛在有害的關鍵字。所有指令都不是強制性的。瀏覽器允許未列示指令的所有來源,或從選用的 default-src
指令衍生值。此外,此標頭的規格隨著時間的推移而不斷演變。在第 23 版之前的 Firefox 和第 10 版之前的 IE 中,其實作為 X-Content-Security-Policy
,而在第 25 版之前的 Chrome 中,則實作為 X-Webkit-CSP
。兩個名稱都已棄用,取代為現在的標準名稱 Content Security Policy
。鑒於指令的數目、兩個棄用的替代名稱,以及對待多次出現之同一標頭和單一標頭中重複指令的方式,開發人員很可能會錯誤地設定此標頭。default-src
指令:
<http auto-config="true">
...
<headers>
...
<content-security-policy policy-directives="default-src '*'" />
</headers>
</http>
script-src
、img-src
、object-src
、style_src
、font-src
、media-src
、frame-src
、connect-src
。這 8 個指令都將一個來源清單做為值,指定網站可存取的網域,以使用該指令所涵蓋的功能。開發人員可使用萬用字元 *
來指示所有或部分來源。其他來源清單關鍵字 (例如 'unsafe-inline'
和 'unsafe-eval'
) 提供更精細的方式來控制 script 執行,但這些是潛在有害的關鍵字。所有指令都不是強制性的。瀏覽器允許未列示指令的所有來源,或從選用的 default-src
指令衍生值。此外,此標頭的規格隨著時間的推移而不斷演變。在第 23 版之前的 Firefox 和第 10 版之前的 IE 中,其實作為 X-Content-Security-Policy
,而在第 25 版之前的 Chrome 中,則實作為 X-Webkit-CSP
。兩個名稱都已棄用,取代為現在的標準名稱 Content Security Policy
。鑒於指令的數目、兩個棄用的替代名稱,以及對待多次出現之同一標頭和單一標頭中重複指令的方式,開發人員很可能會錯誤地設定此標頭。*
) 來配置 *-src
指令。django-csp
設定會設定過度許可且不安全的 default-src
指令:
...
MIDDLEWARE = (
...
'csp.middleware.CSPMiddleware',
...
)
...
CSP_DEFAULT_SRC = ("'self'", '*')
...
Access-Control-Allow-Origin
的新 HTTP 標頭時,存取不同網域間的資料。Web 伺服器可使用此標頭,定義允許使用跨來源要求存取其網域的其他網域。但是,定義標頭時請謹慎小心,因為過度許可的 CORS 原則會允許惡意應用程式以不當方式與受害應用程式通訊,進行導致詐騙、資料竊取、轉送和其他攻擊。
Response.AppendHeader("Access-Control-Allow-Origin", "*");
*
做為 Access-Control-Allow-Origin
表頭的值,表示應用程式的資料可以讓在任何網域上執行的 JavaScript 存取。Access-Control-Allow-Origin
的新 HTTP 標頭時,存取不同網域間的資料。Web 伺服器可使用此標頭,定義允許使用跨來源要求存取其網域的其他網域。但是,定義標頭時請謹慎小心,因為過度許可的 CORS 原則會允許惡意應用程式以不當方式與受害應用程式通訊,進行導致詐騙、資料竊取、轉送和其他攻擊。
<websocket:handlers allowed-origins="*">
<websocket:mapping path="/myHandler" handler="myHandler" />
</websocket:handlers>
*
做為 Access-Control-Allow-Origin
表頭的值,表示應用程式的資料可以讓在任何網域上執行的 JavaScript 存取。Access-Control-Allow-Origin
的新 HTTP 標頭時,存取不同網域間的資料。Web 伺服器可使用此標頭,定義允許使用跨來源要求存取其網域的其他網域。但是,定義標頭時請謹慎小心,因為過度許可的 CORS 原則會允許惡意應用程式以不當方式與受害應用程式通訊,進行導致詐騙、資料竊取、轉送和其他攻擊。
<?php
header('Access-Control-Allow-Origin: *');
?>
*
做為 Access-Control-Allow-Origin
表頭的值,表示應用程式的資料可以讓在任何網域上執行的 JavaScript 存取。Access-Control-Allow-Origin
的新 HTTP 標頭時,存取不同網域間的資料。Web 伺服器可使用此標頭,定義允許使用跨來源要求存取其網域的其他網域。但是,定義標頭時請謹慎小心,因為過度許可的 CORS 原則會允許惡意應用程式以不當方式與受害應用程式通訊,進行導致詐騙、資料竊取、轉送和其他攻擊。
response.addHeader("Access-Control-Allow-Origin", "*")
*
作為 Access-Control-Allow-Origin
表頭的值,表示應用程式的資料可供在任何網域上執行的 JavaScript 存取。Access-Control-Allow-Origin
的新 HTTP 標頭時,存取不同網域間的資料。Web 伺服器可使用此標頭,定義允許使用跨來源要求存取其網域的其他網域。但是,定義標頭時請謹慎小心,因為過度許可的 CORS 原則會允許惡意應用程式以不當方式與受害應用程式通訊,進行導致詐騙、資料竊取、轉送和其他攻擊。
play.filters.cors {
pathPrefixes = ["/some/path", ...]
allowedOrigins = ["*"]
allowedHttpMethods = ["GET", "POST"]
allowedHttpHeaders = ["Accept"]
preflightMaxAge = 3 days
}
*
作為 Access-Control-Allow-Origin
標頭的值,表示應用程式的資料可供在任何網域上執行的 JavaScript 存取。Access-Control-Allow-Origin
的新 HTTP 標頭時,存取不同網域間的資料。Web 伺服器可使用此標頭,定義允許使用跨來源要求存取其網域的其他網域。但是,定義標頭時請謹慎小心,因為過度許可的 CORS 原則會允許惡意應用程式以不當方式與受害應用程式通訊,進行導致詐騙、資料竊取、轉送和其他攻擊。
Response.AddHeader "Access-Control-Allow-Origin", "*"
*
做為 Access-Control-Allow-Origin
表頭的值,表示應用程式的資料可以讓在任何網域上執行的 JavaScript 存取。
WebMessage message = new WebMessage(WEBVIEW_MESSAGE);
webview.postWebMessage(message, Uri.parse("*"));
*
作為目標來源值,代表指令碼會傳送訊息至視窗而不論其來源。
o.contentWindow.postMessage(message, '*');
*
做為目標來源值,代表 Script 會傳送訊息至視窗而不論其來源。Unsafe-URL
可能導致應用程式將敏感網站與使用者資料 (包括階段作業權杖、使用者名稱和密碼) 洩漏給第三方網站。Referrer-Policy
標頭可控制與參照標頭相關的瀏覽器行為。Unsafe-URL
選項會移除所有限制,並傳送包含每個要求的參照標頭。
<http auto-config="true">
...
<headers>
...
<referrer-policy policy="unsafe-url"/>
</headers>
</http>
Content-Security-Policy-Report-Only
標頭為 Web 應用程式作者和管理員提供了監視安全性原則的功能,而不是強制執行原則。此標頭通常在實驗和/或開發網站的安全性原則時使用。當某原則被視為有效時,您可透過改用 Content-Security-Policy
標頭欄位來強制執行此原則。Report-Only
模式中設定內容安全性原則:
<http auto-config="true">
...
<headers>
...
<content-security-policy report-only="true" policy-directives="default-src https://content.cdn.example.com" />
</headers>
</http>
Content-Security-Policy-Report-Only
標頭為 Web 應用程式作者和管理員提供了監視安全性原則的功能,而不是強制執行原則。此標頭通常在實驗和/或開發網站的安全性原則時使用。當某原則視為有效時,您可以透過改用 Content-Security-Policy
標頭來強制執行此原則。Report-Only
模式:
response.content_security_policy_report_only = "*"
SLComposeServiceViewController isContentValid
以在使用收到的不可信賴的資料前對其進行驗證。
#import <MobileCoreServices/MobileCoreServices.h>
@interface ShareViewController : SLComposeServiceViewController
...
@end
@interface ShareViewController ()
...
@end
@implementation ShareViewController
- (void)didSelectPost {
NSExtensionItem *item = self.extensionContext.inputItems.firstObject;
NSItemProvider *itemProvider = item.attachments.firstObject;
...
// Use the received items
...
[self.extensionContext completeRequestReturningItems:@[] completionHandler:nil];
}
...
@end
SLComposeServiceViewController isContentValid
以在使用收到的不可信賴的資料前對其進行驗證。SLComposeServiceViewController isContentValid
回呼方法來進行驗證:
import MobileCoreServices
class ShareViewController: SLComposeServiceViewController {
...
override func didSelectPost() {
let extensionItem = extensionContext?.inputItems.first as! NSExtensionItem
let itemProvider = extensionItem.attachments?.first as! NSItemProvider
...
// Use the received items
...
self.extensionContext?.completeRequestReturningItems([], completionHandler:nil)
}
...
}
webview
使用 URL 與您的應用程式通訊時,接收應用程式應確認傳送者為期望通訊之應用程式允許清單的成員。接收應用程式可以選擇在驗證呼叫 URL 來源時是使用 UIApplicationDelegate application:openURL:options:
還是 UIApplicationDelegate application:openURL:sourceApplication:annotation:
委派方法。UIApplicationDelegate application:openURL:options:
委派方法的以下實作無法確認 IPC 呼叫的傳送者,而是僅處理呼叫 URL:
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options {
NSString *theQuery = [[url query] stringByRemovingPercentEncoding:NSUTF8StringEncoding];
NSArray *chunks = [theQuery componentsSeparatedByString:@"&"];
for (NSString* chunk in chunks) {
NSArray *keyval = [chunk componentsSeparatedByString:@"="]; NSString *key = [keyval objectAtIndex:0];
NSString *value = [keyval objectAtIndex:1];
// Do something with your key and value
}
return YES;
}
wewbview
使用 URL 與您的應用程式通訊時,接收應用程式應確認傳送者為期望通訊之應用程式允許清單的成員。接收應用程式可以選擇在驗證呼叫 URL 來源時是使用 UIApplicationDelegate application:openURL:options:
還是 UIApplicationDelegate application:openURL:sourceApplication:annotation:
委派方法。UIApplicationDelegate application:openURL:options:
委派方法的以下實作無法確認 IPC 呼叫的傳送者,而是僅處理呼叫 URL:
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
return processCall(url)
}
webview
使用某個 URL 與您的應用程式通訊時,接收應用程式應先驗證呼叫 URL,然後再執行進一步的動作。接收應用程式可以選擇是使用 UIApplicationDelegate application:didFinishLaunchingWithOptions:
還是 UIApplicationDelegate application:willFinishLaunchingWithOptions:
委派方法來開啟呼叫 URL。UIApplicationDelegate application:didFinishLaunchingWithOptions:
委派方法的以下實作無法驗證呼叫 URL 並且總是處理不可信賴的 URL:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NS Dictionary *)launchOptions {
return YES;
}
webview
使用某個 URL 與您的應用程式通訊時,接收應用程式應先驗證呼叫 URL,然後再執行進一步的動作。接收應用程式可以選擇是使用 UIApplicationDelegate application:didFinishLaunchingWithOptions:
還是 UIApplicationDelegate application:willFinishLaunchingWithOptions:
委派方法來開啟呼叫 URL。UIApplicationDelegate application:didFinishLaunchingWithOptions:
委派方法的以下實作無法驗證呼叫 URL 並且總是處理不可信賴的 URL:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
return true
}
allowBackup
屬性設定為 true
(預設值) 並定義 <application>
標籤上的 backupAgent
屬性。Environment.getExternalStorageDirectory()
會將參照傳回 Android 裝置的外部儲存裝置。private void WriteToFile(String what_to_write) {
try{
File root = Environment.getExternalStorageDirectory();
if(root.canWrite()) {
File dir = new File(root + "write_to_the_SDcard");
File datafile = new File(dir, number + ".extension");
FileWriter datawriter = new FileWriter(datafile);
BufferedWriter out = new BufferedWriter(datawriter);
out.write(what_to_write);
out.close();
}
}
}
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:ThisDeviceOnly
的可存取性層級仍會備份至 iCloud 和 iTunes。這可能會導致隱私問題,具體視所儲存資料的敏感和隱私程度而定。
...
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSData *token = [@"secret" dataUsingEncoding:NSUTF8StringEncoding];
// Configure KeyChain Item
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id) kSecClass];
[dict setObject:token forKey:(__bridge id)kSecValueData];
...
[dict setObject:(__bridge id)kSecAttrAccessibleWhenUnlocked forKey:(__bridge id) kSecAttrAccessible];
OSStatus error = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
...
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:ThisDeviceOnly
的可存取性層級仍會備份至 iCloud 和 iTunes。這可能會導致隱私問題,具體視所儲存資料的敏感和隱私程度而定。
...
// Configure KeyChain Item
let token = "secret"
var query = [String : AnyObject]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecValueData as String] = token as AnyObject?
...
query[kSecAttrAccessible as String] = kSecAttrAccessibleWhenUnlocked
SecItemAdd(query as CFDictionary, nil)
...
protected void onCreate(Bundle savedInstanceState) {
...
try {
File httpCacheDir = new File(context.getExternalCacheDir(), "http");
long httpCacheSize = 10 * 1024 * 1024; // 10 MiB
HttpResponseCache.install(httpCacheDir, httpCacheSize);
} catch (IOException e) {
Log.i(TAG, "HTTP response cache installation failed:" + e);
}
}
protected void onStop() {
...
HttpResponseCache cache = HttpResponseCache.getInstalled();
if (cache != null) {
cache.flush();
}
}
{app ID}/Library/Caches/com.mycompany.myapp/Cache.db*
檔案中。{app ID}/Library/Caches/com.mycompany.myapp/Cache.db*
檔案中。{app ID}/Library/Caches/com.mycompany.myapp/Cache.db*
檔案中。 URLCache
類別的 diskCapacity
或 memoryCapacity
屬性設定為 0,可有效地停用 HTTP(S) 回應快取系統。但 NSURLCache
說明文件指出,僅當裝置的記憶體或裝置空間均不足時,磁碟上和記憶體內的快取才會被截斷成配置的大小。系統應該使用這兩項設定來釋放系統資源並提高效能,而非將其作為安全性控制。{app ID}/Library/Caches/com.mycompany.myapp/Cache.db*
檔案中。 URLCache
類別的 diskCapacity
或 memoryCapacity
屬性設定為 0,可有效地停用 HTTP(S) 回應快取系統。但 NSURLCache
說明文件指出,僅當裝置的記憶體或裝置空間均不足時,磁碟上和記憶體內的快取才會被截斷成配置的大小。系統應該使用這兩項設定來釋放系統資源並提高效能,而非將其作為安全性控制。NSFileManager
定義,而常數則應該被指派為與 NSFileManager
執行個體相關聯之 NSDictionary
中的 NSFileProtectionKey
金鑰值,以及可以透過使用 NSFileManager
函數 (包括 setAttributes:ofItemAtPath:error:
、attributesOfItemAtPath:error:
和 createFileAtPath:contents:attributes:
) 建立檔案或修改其資料保護類別。此外,相對應的資料保護常數會針對 NSData
物件定義為 NSDataWritingOptions
,以便可以做為 options
引數傳遞到 NSData
函數 writeToURL:options:error:
和 writeToFile:options:error:
。NSFileManager
和 NSData
的各種資料保護類別常數定義如下所示:NSFileProtectionComplete
, NSDataWritingFileProtectionComplete
:NSFileProtectionCompleteUnlessOpen
, NSDataWritingFileProtectionCompleteUnlessOpen
:NSFileProtectionCompleteUntilFirstUserAuthentication
, NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication
:NSFileProtectionNone
, NSDataWritingFileProtectionNone
:NSFileProtectionCompleteUnlessOpen
或 NSFileProtectionCompleteUntilFirstUserAuthentication
標記檔案將會使用衍生自使用者密碼和裝置 UID 的金鑰為其加密,但是在某些情況下資料還是保持可存取的狀態。因此,使用 NSFileProtectionCompleteUnlessOpen
或 NSFileProtectionCompleteUntilFirstUserAuthentication
時應該仔細進行檢閱,以確定是否保證提供進一步的 NSFileProtectionComplete
保護。範例 2:在以下範例中,只有在使用者開啟裝置並首次提供密碼後 (直到下次重新開機),所指定的資料才受到保護:
...
filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
...
NSDictionary *protection = [NSDictionary dictionaryWithObject:NSFileProtectionCompleteUntilFirstUserAuthentication forKey:NSFileProtectionKey];
...
[[NSFileManager defaultManager] setAttributes:protection ofItemAtPath:filepath error:nil];
...
BOOL ok = [testToWrite writeToFile:filepath atomically:YES encoding:NSUnicodeStringEncoding error:&err];
...
...
filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
...
NSData *textData = [textToWrite dataUsingEncoding:NSUnicodeStingEncoding];
...
BOOL ok = [textData writeToFile:filepath options:NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication error:&err];
...
NSFileManager
,而常數則應該被指派為與 NSFileManager
實例相關聯之 Dictionary
中的 NSFileProtectionKey
金鑰值,以及可以透過使用 NSFileManager
函數 (包括 setAttributes(_:ofItemAtPath:)
、attributesOfItemAtPath(_:)
和 createFileAtPath(_:contents:attributes:)
) 建立檔案或修改其資料保護類別。此外,相對應的資料保護常數會針對 NSDataWritingOptions
列舉中的 NSData
物件定義,以便可以做為 options
引數傳遞到 NSData
函數
writeToFile(_:options:)
。NSFileManager
和 NSData
的各種資料保護類別常數定義如下所示:NSFileProtectionComplete
, NSDataWritingOptions.DataWritingFileProtectionComplete
:NSFileProtectionCompleteUnlessOpen
, NSDataWritingOptions.DataWritingFileProtectionCompleteUnlessOpen
:NSFileProtectionCompleteUntilFirstUserAuthentication
, NSDataWritingOptions.DataWritingFileProtectionCompleteUntilFirstUserAuthentication
:NSFileProtectionNone
, NSDataWritingOptions.DataWritingFileProtectionNone
:NSFileProtectionCompleteUnlessOpen
或 NSFileProtectionCompleteUntilFirstUserAuthentication
標記檔案將會使用衍生自使用者密碼和裝置 UID 的金鑰為其加密,但是在某些情況下資料還是保持可存取的狀態。因此,使用 NSFileProtectionCompleteUnlessOpen
或 NSFileProtectionCompleteUntilFirstUserAuthentication
時應該仔細進行檢閱,以確定是否保證提供進一步的 NSFileProtectionComplete
保護。範例 2:在以下範例中,只有在使用者開啟裝置並首次提供密碼後 (直到下次重新開機),所指定的資料才受到保護:
...
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0])
let filename = "\(documentsPath)/tmp_activeTrans.txt"
let protection = [NSFileProtectionKey: NSFileProtectionCompleteUntilFirstUserAuthentication]
do {
try NSFileManager.defaultManager().setAttributes(protection, ofItemAtPath: filename)
} catch let error as NSError {
NSLog("Unable to change attributes: \(error.debugDescription)")
}
...
BOOL ok = textToWrite.writeToFile(filename, atomically:true)
...
...
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0])
let filename = "\(documentsPath)/tmp_activeTrans.txt"
...
BOOL ok = textData.writeToFile(filepath, options: .DataWritingFileProtectionCompleteUntilFirstUserAuthentication);
...
kSecAttrAccessible
金鑰的值。各個金鑰鏈可存取性常數的定義如下所示:kSecAttrAccessibleAfterFirstUnlock
:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:kSecAttrAccessibleAfterFirstUnlock
標記金鑰鏈項目將會使用衍生自使用者密碼和裝置 UID 的金鑰進行加密,但是在某些情況下資料仍然保持可存取狀態。因此,使用 kSecAttrAccessibleAfterFirstUnlock
時應該仔細進行檢閱,確定是否保證提供進一步的保護。
...
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSData *token = [@"secret" dataUsingEncoding:NSUTF8StringEncoding];
// Configure KeyChain Item
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id) kSecClass];
[dict setObject:token forKey:(__bridge id)kSecValueData];
...
[dict setObject:(__bridge id)kSecAttrAccessibleAfterFirstUnlock forKey:(__bridge id) kSecAttrAccessible];
OSStatus error = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
...
kSecAttrAccessible
金鑰的值。各個金鑰鏈可存取性常數的定義如下所示:kSecAttrAccessibleAfterFirstUnlock
:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:kSecAttrAccessibleAfterFirstUnlock
標記金鑰鏈項目將會使用衍生自使用者密碼和裝置 UID 的金鑰進行加密,但是在某些情況下資料仍然保持可存取狀態。因此,使用 kSecAttrAccessibleAfterFirstUnlock
時應該仔細進行檢閱,確定是否保證提供進一步的保護。
...
// Configure KeyChain Item
let token = "secret"
var query = [String : AnyObject]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecValueData as String] = token as AnyObject?
...
query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock
SecItemAdd(query as CFDictionary, nil)
...
NSFileManager
定義,而常數則應該被指派為與 NSFileManager
執行個體相關聯之 NSDictionary
中的 NSFileProtectionKey
金鑰值,以及可以透過使用 NSFileManager
函數 (包括 setAttributes:ofItemAtPath:error:
、attributesOfItemAtPath:error:
和 createFileAtPath:contents:attributes:
) 建立檔案或修改其資料保護類別。此外,相對應的資料保護常數會針對 NSData
物件定義為 NSDataWritingOptions
,以便可以做為 options
引數傳遞到 NSData
函數 writeToURL:options:error:
和 writeToFile:options:error:
。NSFileManager
和 NSData
的各種資料保護類別常數定義如下所示:NSFileProtectionComplete
, NSDataWritingFileProtectionComplete
:NSFileProtectionCompleteUnlessOpen
, NSDataWritingFileProtectionCompleteUnlessOpen
:NSFileProtectionCompleteUntilFirstUserAuthentication
, NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication
:NSFileProtectionNone
, NSDataWritingFileProtectionNone
:NSFileProtectionNone
也會導致使用完全以裝置 UID 為基礎的衍生金鑰進行加密。如此一來,在裝置開機的任何時候 (包括以密碼鎖定時或正在開機時),此類檔案都會處於可存取的狀態。因此,使用 NSFileProtectionNone
時應該仔細進行檢閱,以確定是否保證使用較嚴格的資料保護類別提供進一步的保護。範例 2:在以下範例中,指定的資料未受保護 (在裝置開機的任何時候均可存取):
...
filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
...
NSDictionary *protection = [NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey];
...
[[NSFileManager defaultManager] setAttributes:protection ofItemAtPath:filepath error:nil];
...
BOOL ok = [testToWrite writeToFile:filepath atomically:YES encoding:NSUnicodeStringEncoding error:&err];
...
...
filepath = [self.GetDocumentDirectory stringByAppendingPathComponent:self.setFilename];
...
NSData *textData = [textToWrite dataUsingEncoding:NSUnicodeStingEncoding];
...
BOOL ok = [textData writeToFile:filepath options:NSDataWritingFileProtectionNone error:&err];
...
NSFileManager
,而常數則應該被指派為與 NSFileManager
實例相關聯之 Dictionary
中的 NSFileProtectionKey
金鑰值。可以透過使用 NSFileManager
函數 (包括 setAttributes(_:ofItemAtPath:)
、attributesOfItemAtPath(_:)
和 createFileAtPath(_:contents:attributes:)
) 建立檔案或修改其資料保護類別。此外,相對應的資料保護常數會針對 NSDataWritingOptions
列舉中的 NSData
物件定義,以便可以做為 options
引數傳遞到 NSData
函數,例如
writeToFile(_:options:)
。NSFileManager
和 NSData
的各種資料保護類別常數定義如下所示:NSFileProtectionComplete
, NSDataWritingOptions.DataWritingFileProtectionComplete
:NSFileProtectionCompleteUnlessOpen
, NSDataWritingOptions.DataWritingFileProtectionCompleteUnlessOpen
:NSFileProtectionCompleteUntilFirstUserAuthentication
, NSDataWritingOptions.DataWritingFileProtectionCompleteUntilFirstUserAuthentication
:NSFileProtectionNone
, NSDataWritingOptions.DataWritingFileProtectionNone
:NSFileProtectionNone
也會導致使用完全以裝置 UID 為基礎的衍生金鑰進行加密。如此一來,在裝置開機的任何時候 (包括以密碼鎖定時或正在開機時),此類檔案都會處於可存取的狀態。因此,使用 NSFileProtectionNone
時應該仔細進行檢閱,以確定是否保證使用較嚴格的資料保護類別提供進一步的保護。範例 2:在以下範例中,指定的資料未受保護 (只要裝置開機便可存取):
...
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0])
let filename = "\(documentsPath)/tmp_activeTrans.txt"
let protection = [NSFileProtectionKey: NSFileProtectionNone]
do {
try NSFileManager.defaultManager().setAttributes(protection, ofItemAtPath: filename)
} catch let error as NSError {
NSLog("Unable to change attributes: \(error.debugDescription)")
}
...
BOOL ok = textToWrite.writeToFile(filename, atomically:true)
...
...
let documentsPath = NSURL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0])
let filename = "\(documentsPath)/tmp_activeTrans.txt"
...
BOOL ok = textData.writeToFile(filepath, options: .DataWritingFileProtectionNone);
...
kSecAttrAccessible
金鑰的值。各個金鑰鏈可存取性常數的定義如下所示:kSecAttrAccessibleAfterFirstUnlock
:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:kSecAttrAccessibleAlways
也會導致使用完全以裝置 UID 為基礎的衍生金鑰進行加密。如此一來,在裝置開機的任何時候 (包括以密碼鎖定時或正在開機時),此類檔案都會處於可存取的狀態。因此,使用 kSecAttrAccessibleAlways
時應該仔細進行檢閱,確定是否能保證具有較嚴格金鑰鏈可存取性層級的進一步保護。
...
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSData *token = [@"secret" dataUsingEncoding:NSUTF8StringEncoding];
// Configure KeyChain Item
[dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id) kSecClass];
[dict setObject:token forKey:(__bridge id)kSecValueData];
...
[dict setObject:(__bridge id)kSecAttrAccessibleAlways forKey:(__bridge id) kSecAttrAccessible];
OSStatus error = SecItemAdd((__bridge CFDictionaryRef)dict, NULL);
...
kSecAttrAccessible
金鑰的值。各個金鑰鏈可存取性常數的定義如下所示:kSecAttrAccessibleAfterFirstUnlock
:kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
:kSecAttrAccessibleAlways
:kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly
:kSecAttrAccessibleAlwaysThisDeviceOnly
:kSecAttrAccessibleWhenUnlocked
:kSecAttrAccessibleWhenUnlockedThisDeviceOnly
:kSecAttrAccessibleAlways
也會導致使用完全以裝置 UID 為基礎的衍生金鑰進行加密。如此一來,在裝置開機的任何時候 (包括以密碼鎖定時或正在開機時),此類檔案都會處於可存取的狀態。因此,使用 kSecAttrAccessibleAlways
時應該仔細進行檢閱,確定是否能保證具有較嚴格金鑰鏈可存取性層級的進一步保護。
...
// Configure KeyChain Item
let token = "secret"
var query = [String : AnyObject]()
query[kSecClass as String] = kSecClassGenericPassword
query[kSecValueData as String] = token as AnyObject?
...
query[kSecAttrAccessible as String] = kSecAttrAccessibleAlways
SecItemAdd(query as CFDictionary, nil)
...