iOS請(qǐng)求方法和網(wǎng)絡(luò)安全

GET和POST請(qǐng)求

GET和POST請(qǐng)求簡(jiǎn)介

GET請(qǐng)求模擬登陸

POST請(qǐng)求模擬登陸

GET和POST的對(duì)比

保存用戶信息到偏好設(shè)置

網(wǎng)絡(luò)安全

Base64編碼解碼

MD5加密

鑰匙串

GET和POST請(qǐng)求,是HTTP協(xié)議下常用的兩種請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)的方法。

GET和POST請(qǐng)求

簡(jiǎn)介

GET請(qǐng)求:

GET的本質(zhì)是得.

從服務(wù)器獲取數(shù)據(jù),效率比POST高.

GET請(qǐng)求能夠被緩存

在 HTTP 協(xié)議定義中,沒(méi)有對(duì)GET請(qǐng)求的數(shù)據(jù)大小限制,不過(guò)因?yàn)闉g覽器不同一般限制在 2~8K 之間

GET發(fā)送請(qǐng)求時(shí),URL中除了資源路徑以外,所有的參數(shù)(查詢字符串)也包裝在URL中,并且服務(wù)器的訪問(wèn)日志會(huì)記錄,不要傳遞敏感信息

瀏覽器可以監(jiān)視GET請(qǐng)求.

POST請(qǐng)求

POST的本質(zhì)是給.

向服務(wù)器發(fā)送數(shù)據(jù),也可以獲得服務(wù)器處理之后的結(jié)果,效率不如GET.

POST請(qǐng)求不能被緩存.

POST提交數(shù)據(jù)比較大,大小靠服務(wù)器的設(shè)定值限制,PHP通常限定 2M.

POST發(fā)送請(qǐng)求時(shí),URL中只有資源路徑,但不包含參數(shù),服務(wù)器日志不會(huì)記錄參數(shù),相對(duì)更安全.

參數(shù)被包裝成二進(jìn)制的數(shù)據(jù)體,格式與 GET 基本一致,只是不包含 ?.

注意 : 所有涉及到用戶隱私的數(shù)據(jù)(密碼,銀行卡號(hào))一定記住使用 POST 方式傳遞.

瀏覽器可以監(jiān)視POST請(qǐng)求.但是不容易捕捉到.

GET請(qǐng)求模擬登陸

準(zhǔn)備界面

登陸按鈕點(diǎn)擊事件

- (IBAction)loginClick:(id)sender

{

NSString *userName = self.userNameTextField.text;

NSString *psd = self.psdTextField.text;

NSString *loginURLString = [NSString stringWithFormat:@"http://xxx/php/login/login.php?username=%@&password=%@",userName,psd];

/*

注意 :

GET請(qǐng)求時(shí),問(wèn)號(hào)`?`后面的查詢字符串里面不能有中文或者空格.如果有就需要使用%轉(zhuǎn)義.不然URL會(huì)為nil

POST請(qǐng)求時(shí),請(qǐng)求體里面可以有中文.

URLQueryAllowedCharacterSet : 百分號(hào)轉(zhuǎn)義查詢字符串

*/

loginURLString = [loginURLString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];

// URL

NSURL *URL = [NSURL URLWithString:loginURLString];

// 發(fā)起和啟動(dòng)任務(wù)

[[[NSURLSession sharedSession] dataTaskWithURL:URL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

// 錯(cuò)誤處理

if (error == nil && data != nil) {

// json反序列化

NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

// 判斷是否登陸成功

if ([result[@"userId"] integerValue] == 1) {

NSLog(@"登陸成功");

} else {

NSLog(@"登陸失敗");

}

} else {

NSLog(@"%@",error);

}

}] resume];

}

```

* 注意:`URL參數(shù)中如果有漢字或空格或者特殊字符,需要進(jìn)行百分號(hào)轉(zhuǎn)義.否則,創(chuàng)建NSURL會(huì)返回nil;`

* ####POST請(qǐng)求模擬登陸

* 準(zhǔn)備界面

![](http://upload-images.jianshu.io/upload_images/3552201-3c6935567e785c78.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

* 登陸按鈕點(diǎn)擊事件

- (IBAction)loginClick:(id)sender

{

// URL

NSURL *URL = [NSURL URLWithString:@"http://xxx/php/login/login.php"];

// 創(chuàng)建請(qǐng)求

NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:URL];

// 設(shè)置請(qǐng)求方法

requestM.HTTPMethod = @"POST";

// 設(shè)置請(qǐng)求體 : POST做登陸和注冊(cè)時(shí)需要額外的發(fā)送請(qǐng)求體

requestM.HTTPBody = [self getHTTPBody];

// 發(fā)起和啟動(dòng)任務(wù)

[[[NSURLSession sharedSession] dataTaskWithRequest:requestM completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

// 錯(cuò)誤處理

if (error == nil && data != nil) {

// 反序列化json

NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

// 判斷是否登陸成功

if ([result[@"userId"] intValue] == 1) {

NSLog(@"登陸成功");

} else {

NSLog(@"登陸失敗");

}

} else {

NSLog(@"%@",error);

}

}] resume];

}

```

設(shè)置請(qǐng)求體

- (NSData *)getHTTPBody

{

NSString *body = [NSString stringWithFormat:@"username=%@&password=%@",self.userNameTextField.text,self.psdTextField.text];

NSData *HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];

return HTTPBody;

}

```

GET和POST的對(duì)比

URL

GET:http://xxx/php/login/login.php?username=zhangsan&password=zhang

POST:http://xxx/php/login/login.php

GET請(qǐng)求

URL 中在指定資源路徑后面,包含了所有參數(shù)(查詢字符串).

GET是網(wǎng)絡(luò)訪問(wèn)使用頻率最高的方法.從服務(wù)器獲取數(shù)據(jù)默認(rèn)方法就是 GET.

POST請(qǐng)求

URL 中不包含任何參數(shù),直接指定資源路徑即可.沒(méi)有 ?.

POST請(qǐng)求 需要指定HTTP的訪問(wèn)方法為:@"POST".

所有的參數(shù)都在請(qǐng)求體中指定.

保存用戶信息到偏好設(shè)置

定義宏

*#define userName @"userName"

*#define psd @"psd"

保存用戶信息到偏好設(shè)置

- (void)saveUserInfos

{

[[NSUserDefaults standardUserDefaults] setObject:self.userNameTextField.text forKey:userName];

[[NSUserDefaults standardUserDefaults] setObject:self.psdTextField.text forKey:psd];

}

```

* 從偏好設(shè)置獲取用戶信息

- (void)readUserInfos

{

self.userNameTextField.text = [[NSUserDefaults standardUserDefaults] objectForKey:userName];

self.psdTextField.text = [[NSUserDefaults standardUserDefaults] objectForKey:psd];

}

```

登陸成功,保存用戶信息到偏好設(shè)置

- (void)viewDidLoad {

[super viewDidLoad];

// 程序啟動(dòng)之后,從偏好設(shè)置獲取用戶信息

[self readUserInfos];

}

- (IBAction)loginClick:(id)sender

{

// URL

NSURL *URL = [NSURL URLWithString:@"http://xxx/php/login/login.php"];

// 創(chuàng)建請(qǐng)求

NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:URL];

// 設(shè)置請(qǐng)求方法

requestM.HTTPMethod = @"POST";

// 設(shè)置請(qǐng)求體 : POST做登陸和注冊(cè)時(shí)需要額外的發(fā)送請(qǐng)求體

requestM.HTTPBody = [self getHTTPBody];

// 發(fā)起和啟動(dòng)任務(wù)

[[[NSURLSession sharedSession] dataTaskWithRequest:requestM completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

// 錯(cuò)誤處理

if (error == nil && data != nil) {

// 反序列化json

NSDictionary *result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];

// 判斷是否登陸成功

if ([result[@"userId"] intValue] == 1) {

NSLog(@"登陸成功");

// 登陸成功之后,保存用戶信息到偏好設(shè)置

[self saveUserInfos];

} else {

NSLog(@"登陸失敗");

}

} else {

NSLog(@"%@",error);

}

}] resume];

}

```

* 程序啟動(dòng),從偏好設(shè)置讀取用戶信息

- (void)viewDidLoad {

[super viewDidLoad];

// 程序啟動(dòng),從偏好設(shè)置讀取用戶信息

[self readUserInfos];

}

```

網(wǎng)絡(luò)安全

Base64編碼解碼

簡(jiǎn)介

是網(wǎng)絡(luò)上使用最廣泛的編碼系統(tǒng),能夠?qū)⑷魏味M(jìn)制數(shù)據(jù),轉(zhuǎn)換成只有 65 個(gè)字符組成的文本文件.

編碼后的數(shù)據(jù)由 a-z A-Z 0-9 + / = 表示.

base64 編碼后的結(jié)果能夠反算,不夠安全.

base64 是所有現(xiàn)代加密算法的基礎(chǔ)算法.

原理

把一個(gè)字符轉(zhuǎn)換成二進(jìn)制取出前6位查表.

不夠6位的時(shí)候補(bǔ)0,如果是8位,則補(bǔ)4個(gè)0,編碼后連接兩個(gè)==.

如果最后是4位,補(bǔ)2個(gè)0,編碼后連接一個(gè)=.

編碼之后文件會(huì)變大,因?yàn)橛醒a(bǔ)0.

加密和解密

發(fā)送隱私信息時(shí)需要加密

提示 : 服務(wù)器上保存的私密信息是機(jī)密之后的數(shù)據(jù)

保存隱私信息時(shí)也需要加密

讀取保存的隱私信息時(shí)需要解密

網(wǎng)絡(luò)應(yīng)用程序的數(shù)據(jù)安全

Base64編碼解碼模擬加密解密代碼實(shí)現(xiàn)

base64編碼 ===> 模擬加密

/// base64編碼---加密 : 傳入需要"加密"的字符串,返回"加密"之后的字符串

- (NSString *)base64Encode:(NSString *)str

{

// 1.將需要加密的數(shù)據(jù)轉(zhuǎn)成二進(jìn)制,因?yàn)锽ase64的編碼和解碼都是針對(duì)二進(jìn)制的

NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];

// 2.把二進(jìn)制數(shù)據(jù)編碼之后,直接轉(zhuǎn)成字符串

NSString *encodeStr = [data base64EncodedStringWithOptions:0];

// 3.返回結(jié)果

return encodeStr;

}

base64解碼 ===> 模擬解密

/// base64解碼---解密

- (NSString *)base64Decode:(NSString *)encodeStr

{

if (encodeStr.length == 0) {

return nil;

}

// 1.把編碼之后的字符串解碼成二進(jìn)制

NSData *data = [[NSData alloc] initWithBase64EncodedString:encodeStr options:0];

// 2.把解碼之后的二進(jìn)制轉(zhuǎn)換成字符串

NSString *decodeStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

// 3. 返回結(jié)果

return decodeStr;

}

發(fā)送用戶信息時(shí)先"加密".

- (NSData *)getHTTPBody

{

// 發(fā)送密碼之前先加密

NSString *password = [self base64Encode:self.psdTextField.text];

NSString *body = [NSString stringWithFormat:@"username=%@&password=%@",self.userNameTextField.text,password];

NSData *HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];

return HTTPBody;

}

保存用戶信息之前"加密"處理.

- (void)saveUserInfos

{

[[NSUserDefaults standardUserDefaults] setObject:self.userNameTextField.text forKey:userName];

// 密碼保存之前先加密

NSString *password = [self base64Encode:self.psdTextField.text];

[[NSUserDefaults standardUserDefaults] setObject:password forKey:psd];

}

讀取本地"加密"的用戶信息時(shí)需要"解密".

- (void)readUserInfos

{

self.userNameTextField.text = [[NSUserDefaults standardUserDefaults] objectForKey:userName];

// 取出密碼之前先解密

NSString *password = [self base64Decode:[[NSUserDefaults standardUserDefaults] objectForKey:psd]];

self.psdTextField.text = password;

}

Base64編碼的好處壞處

好處:使用Base64編碼之后,不能直接看到用戶密碼的明文.

問(wèn)題:但是Base64編碼解碼的算法是公開(kāi)的,并且算法可逆,安全性并不好.

MD5加密

簡(jiǎn)介

對(duì)任意的數(shù)據(jù)進(jìn)行計(jì)算,生成固定長(zhǎng)度的字符串.32個(gè)字符.

一般用來(lái)加密密碼.

有時(shí)候也用來(lái)驗(yàn)證文件下載時(shí),是否被篡改過(guò).

MD5終端命令

# 得到文件的MD5值

$ md5 文件名

# 得到字符串的MD5值

md5 -s "string"

MD5加密方案

先導(dǎo)入分類(lèi) #import "NSString+Hash.h"

方案一:

password = [self.psdTextField.text md5String];

Base64與MD5對(duì)比

Base64編碼 : "加密"簡(jiǎn)單,算法可逆.毫無(wú)安全性可言.不能用來(lái)加密密碼.

MD5 : 加密過(guò)程復(fù)雜,算法不可逆,安全性高,常用來(lái)加密密碼等用戶的敏感信息.但是簡(jiǎn)單的密碼MD5加密之后可以暴力破解.

暴力破解網(wǎng)站 :cmd5

方案二 : 密碼加鹽

如果原始密碼過(guò)于簡(jiǎn)單,直接進(jìn)行MD5加密是很容易被暴力破解的.

為了增強(qiáng)密碼的安全性,防止加密的密碼被暴力破解,可以向原始密碼中加鹽.

鹽 : 服務(wù)器端和客戶端約定的一個(gè)字符串.

MD5+鹽 : 原始密碼+鹽拼接出新的密碼字符串,再進(jìn)行MD加密.

以上為加一勺鹽,比單純的直接MD5加密安全性要高.

鹽要足夠的咸,越咸越安全.

// 鹽

NSString *salt = @"123zxcASD!@#";

password = [[self.psdTextField.text stringByAppendingString:salt] md5String];

方案三 : HMAC

HMAC : 加兩勺鹽.加兩勺鹽的密碼加密強(qiáng)度比加一勺鹽要高.

原理 : 原始密碼+鹽進(jìn)行MD5計(jì)算,結(jié)算的結(jié)果+原始密碼再進(jìn)行MD5計(jì)算.

// 鹽

NSString *salt = @"123zxcASD!@#";

password = [self.psdTextField.text hmacMD5StringWithKey:salt];

注意

不能用不可逆的加密算法加密密碼并保存到本地.因?yàn)椴豢赡娴募用芩惴用艿臄?shù)據(jù)幾乎不能還原回來(lái).

蘋(píng)果提供了鑰匙串專(zhuān)門(mén)保存用戶的私密信息到本地.

獲取請(qǐng)求體的方法

- (NSData *)getHTTPBody

{

// 發(fā)送密碼之前先加密

NSString *password;

// Base64編碼模擬加密

//? ? password = [self base64Encode:self.psdTextField.text];

// MD5加密

//? ? password = [self.psdTextField.text md5String];

#pragma MD5加鹽

// 1. 加一勺鹽,加密強(qiáng)度比單純的MD5加密更高.越咸安全性越高

// 加鹽的字符串 : 服務(wù)器端和客戶端約定的一個(gè)字符串.

//? ? NSString *salt = @"123zxcASD!@#";

//? ? password = [[self.psdTextField.text stringByAppendingString:salt] md5String];

// 2. HMAC : 加兩勺鹽.原始密碼+鹽進(jìn)行MD5計(jì)算,計(jì)算的結(jié)果+原始密碼再進(jìn)行MD5計(jì)算

NSString *salt = @"123zxcASD!@#";

password = [self.psdTextField.text hmacMD5StringWithKey:salt];

NSString *body = [NSString stringWithFormat:@"username=%@&password=%@",self.userNameTextField.text,password];

NSData *HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];

return HTTPBody;

}

鑰匙串

簡(jiǎn)介

safari 偏好設(shè)置里面可以讀取到保存到鑰匙串中的密碼.

使用 AES 256 加密算法,能夠保證用戶密碼的安全.

鑰匙串訪問(wèn)SDK,是蘋(píng)果在 iOS 7.0.3 版本以后公布的.鑰匙串訪問(wèn)的SDK是純 C 語(yǔ)言的.

鑰匙串訪問(wèn)的密碼保存在哪里?只有蘋(píng)果知道!是為了進(jìn)一步保障用戶的密碼安全!

鑰匙串訪問(wèn)的第三方框架,是對(duì) C 框架的封裝,可以不用看源代碼.

框架地址 :https://github.com/soffes/sskeychain

sskeychain提供的常用的方法

/// 所有賬戶

+ (NSArray *)allAccounts;

/// 獲取所有賬戶信息

+ (NSArray *)accountsForService:(NSString *)serviceName;

/// 獲取賬號(hào)密碼

+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;

/// 刪除賬號(hào)密碼

+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;

/// 將賬號(hào)密碼保存在鑰匙串

+ (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account;

密碼保存到鑰匙串

先導(dǎo)入頭文件 : #import "SSKeychain.h"

/*

參數(shù)1 : 要保存到鑰匙串的密碼

參數(shù)2 : 保存哪個(gè)應(yīng)用的密碼

參數(shù)3 : 保存哪個(gè)賬號(hào)的密碼

*/

[SSKeychain setPassword:self.psdTextField.text forService:[NSBundle mainBundle].bundleIdentifier account:self.userNameTextField.text];

從鑰匙串讀取密碼

self.psdTextField.text = [SSKeychain passwordForService:[NSBundle mainBundle].bundleIdentifier account:self.userNameTextField.text];

感謝讀到最后的朋友,最后祝大家新年快樂(lè),請(qǐng)點(diǎn)贊支持一下,謝謝!

作者:MiracleGl

鏈接:http://www.lxweimin.com/p/69dd436c7416

來(lái)源:簡(jiǎn)書(shū)

著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。