1. 程式人生 > >HTTP認證-摘要認證

HTTP認證-摘要認證

摘要認證 digest authentication   ← HTTP1.1提出的基本認證的替代方法

    伺服器端以nonce進行質詢,客戶端以使用者名稱,密碼,nonceHTTP方法,請求的URI等資訊為基礎產生的response資訊進行認證的方式。

     不包含密碼的明文傳遞

    

    摘要認證步驟:

     1.

 客戶端訪問一個受http摘要認證保護的資源。

     2. 伺服器返回401狀態以及nonce等資訊,要求客戶端進行認證。

HTTP/1.1 401 Unauthorized

WWW-Authenticate: Digest

realm="[email protected]",

qop="auth,auth-int",

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",

opaque="5ccc069c403ebaf9f0171e9517f40e41"

     3.

 客戶端將以使用者名稱,密碼,nonce值,HTTP方法, 和被請求的URI為校驗值基礎而加密(預設為MD5演算法)的摘要資訊返回給伺服器。

           認證必須的五個情報:

     ? realm : 響應中包含資訊

     ? nonce  響應中包含資訊

     ? username  使用者名稱

     ? digest-uri 

 請求的URI

     ? response  以上面四個資訊加上密碼資訊,使用MD5演算法得出的字串。


Authorization: Digest 

username="Mufasa",   客戶端已知資訊

realm="[email protected]",    伺服器端質詢響應資訊

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  ← 伺服器端質詢響應資訊

uri="/dir/index.html",  客戶端已知資訊

qop=auth,    伺服器端質詢響應資訊

nc=00000001,  客戶端計算出的資訊

cnonce="0a4f113b",  客戶端計算出的客戶端nonce

response="6629fae49393a05397450978507c4ef1",  最終的摘要資訊 ha3

opaque="5ccc069c403ebaf9f0171e9517f40e41"   伺服器端質詢響應資訊

     4. 如果認證成功,則返回相應的資源。如果認證失敗,則仍返回401狀態,要求重新進行認證。


    特記事項:

     1. 避免將密碼作為明文在網路上傳遞,相對提高了HTTP認證的安全性。

     2. 當用戶為某個realm首次設定密碼時,伺服器儲存的是以使用者名稱,realm,密碼為基礎計算出的雜湊值(ha1),而非密碼本身。

     3. 如果qop=auth-int,在計算ha2時,除了包括HTTP方法,URI路徑外,還包括請求實體主體,從而防止PUTPOST請求表示被人篡改。

     4. 但是因為nonce本身可以被用來進行摘要認證,所以也無法確保認證後傳遞過來的資料的安全性。


    nonce:隨機字串,每次返回401響應的時候都會返回一個不同的nonce 

    nounce:隨機字串,每個請求都得到一個不同的nounce 

       MD5(Message Digest algorithm 5,資訊摘要演算法)

          使用者名稱:realm:密碼  ha1

          HTTP請求方式:URI  ha2

          ha1:nonce:nc:cnonce:qop:ha2  ha3

以上摘自:http://blog.csdn.net/hotnet522/article/details/5824716


下面是程式碼:

-(void)initInterNetImageData:(NSString *)urlStr name:(NSString *)username password:(NSString *)password{

    

    NSLog(@"urlStr====%@",urlStr);

            NSURL *url1=[NSURLURLWithString:[urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

            //自定義的request

            NSMutableURLRequest *request1 = [NSMutableURLRequestrequestWithURL:url1];

            //請求過期時間

            request1.timeoutInterval = 5;

            //get請求

            request1.HTTPMethod = @"GET";

            

            NSURLSession * session1=[NSURLSessionsharedSession];

            [[session1 dataTaskWithRequest:request1completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError * _Nullable error) {

                NSHTTPURLResponse * Hresponse1=(NSHTTPURLResponse *)response;

                NSLog(@"response=======%@",Hresponse1);

                if (Hresponse.statusCode==401) {

                    NSArray * UrlArr=[urlStr componentsSeparatedByString:@"/"];

                    NSMutableString * urlStr2=[[NSMutableStringalloc]init];

                    if ([UrlArr isKindOfClass:[NSArrayclass]]) {

                        for (int i=3; i<UrlArr.count; i++) {

                            

                            [urlStr2 appendFormat:@"/%@",UrlArr[i]];

                            

                        }

                    }


                    NSString * autho=[selfhandle401Code:Hresponse1 url2:urlStr2 user:username pass:password];

                    

                    NSMutableURLRequest *request2 = [[NSMutableURLRequestalloc]initWithURL:url];

                    request2.timeoutInterval=5;

                    [request2 addValue:autho forHTTPHeaderField:@"Authorization"];

                    [request2 setHTTPMethod:@"GET"];

                    

                    NSURLSession * session2=[NSURLSessionsharedSession];

                    [[session2 dataTaskWithRequest:request2completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError * _Nullable error) {

                        NSHTTPURLResponse * Hresponse2=(NSHTTPURLResponse *)response;

                        if (data.length>100) {

                            NSString *URLResult = [Hresponse2.URLabsoluteString];

                            NSLog(@"URLResult=======%@",URLResult);

                            [self chaxun:URLResult data:data];

                        }

                    }]resume];

                    

                }

                

            }] resume] ;


    

}



-(NSString *)handle401Code:(NSHTTPURLResponse *)response url2:(NSString *)url2 user:(NSString *)username pass:(NSString *)password

{


    NSString *wwwAuthenticate = [[response allHeaderFields ]objectForKey:@"Www-Authenticate"];

    NSString *realm = nil;

    NSString *qop = nil;

    NSString*nonce = nil;

    NSString *opaque = nil;

    //解析wwwAuthenticate

    NSArray *arr = [wwwAuthenticate componentsSeparatedByString:@","];

    for (NSString *perStr in arr) {

        NSRange range= [perStr rangeOfString:@"="];

        //提取=後面的

        NSString *perStrFirst = [perStr substringToIndex:range.location];

        NSString *perStrSecond =[perStr substringWithRange:NSMakeRange(range.location+range.length+1,perStr.length-range.location-range.length-2)];

        if ([perStrFirst rangeOfString:@"realm"].location !=NSNotFound) {

            realm = perStrSecond;

            NSLog(@"realm = %@",realm);

        }

        if ([perStrFirst rangeOfString:@"qop"].location !=NSNotFound) {

            qop = perStrSecond;

            NSLog(@"qop = %@",qop);

        }

        if ([perStrFirst rangeOfString:@"nonce"].location !=NSNotFound) {

            nonce=perStrSecond;

            NSLog(@"nonce = %@",nonce);

        }

        if ([perStrFirst rangeOfString:@"opaque"].location !=NSNotFound) {

            opaque=perStrSecond;

            NSLog(@"opaque = %@",opaque);

        }

        

    }

    

    // 以從1970年到現在時間差作為branch的值

    NSTimeInterval time = [[NSDatedate]timeIntervalSince1970];

    long long int t = (long long int)time;

    NSString *cnonce = [[NSStringalloc]initWithFormat:@"%lld%d",t,arc4random()+10000];

    

    static unsigned int ncCnt = 1;

    NSString *nc = [[NSStringalloc]initWithFormat:@"%d",++ncCnt];

    

    NSString *algorithm = @"MD5";

    

    NSString *uri = url2;

    

    NSString *method = @"GET";

    

    NSString *md5First = [[NSStringalloc]initWithFormat:@"%@:%@:%@",username,realm,password];

    NSString * ha1=[md5First MD5Digest];

    

    NSString *md5Second = [[NSStringalloc]initWithFormat:@"%@:%@",method,uri];

    NSString * ha2=[md5Second MD5Digest];

    

    NSString *responseStr = [[NSStringalloc]initWithFormat:@"%@:%@:%@:%@:%@:%@",ha1,nonce,nc,cnonce,qop,ha2];

    

    NSString *ha3 = [responseStr MD5Digest];

    NSString *authorization = nil;

    if (opaque != nil) {

        authorization = [[NSStringalloc]initWithFormat:@"Digest username=\"%@\",realm=\"%@\",nonce=\"%@\",uri=\"%@\",response=\"%@\", opaque=\"%@\",qop=%@,nc=\"%@\",cnonce=\"%@\",algorithm=\"%@\"",@"admin",realm,nonce,uri,ha3,opaque,qop,nc,cnonce,algorithm];

        

    }else{

        authorization = [[NSStringalloc]initWithFormat:@"Digest username=\"%@\",realm=\"%@\",nonce=\"%@\",uri=\"%@\",response=\"%@\", qop=\"%@\",nc=\"00000001\",cnonce=\"%@\",algorithm=\"%@\"",@"admin",realm,nonce,uri,ha3,qop,cnonce,algorithm];

    }

    

    NSLog(@"authorization=========%@",authorization);

    

    return authorization;

}



#import <CommonCrypto/CommonDigest.h>

#import "NSString+MD5.h"


@implementation NSString (MD5)


- (NSString *)MD5Digest

{

    const char* input = [self UTF8String];

    unsigned char result[CC_MD5_DIGEST_LENGTH];

    CC_MD5(input, (CC_LONG)strlen(input), result);

    

    NSMutableString *digest = [NSMutableStringstringWithCapacity:CC_MD5_DIGEST_LENGTH *2];

    for (NSInteger i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {

        [digest appendFormat:@"%02x", result[i]];

    }

    

    return digest;

}


個人遇到的問題總結:

1.-(NSString *)handle401Code:(NSHTTPURLResponse *)response url2:(NSString *)url2 user:(NSString *)username pass:(NSString *)password