ホームページ  >  記事  >  バックエンド開発  >  PHP、iOS は JSPatch 基本と RSA、AES 暗号化を使用します

PHP、iOS は JSPatch 基本と RSA、AES 暗号化を使用します

WBOY
WBOYオリジナル
2016-06-20 12:34:46932ブラウズ

JSPatch を使用する場合、理論上、JS スクリプトは任意の OC メソッドを呼び出すことができ、非常に高い権限を持ちます。HTTP 送信中に中間者攻撃によって JS コードが改ざんされると、大きな損害が発生します。 。

このような状況を踏まえて

1. 服务器尽量使用https传输2. 对传输的代码做好加密和校验

次に、サーバー側でphp、モバイル側でiOSを使用して、主に2番目の方法を扱います

RSAアルゴリズム

RSA は現在最も影響力のある公開キー暗号化アルゴリズムであり、これまでに知られているほとんどの暗号化攻撃に対抗でき、公開キー データ暗号化標準として ISO によって推奨されています。

RSA アルゴリズムは、データ送信の暗号化によく使用される非対称暗号化アルゴリズムです。デジタル ダイジェスト アルゴリズムと組み合わせると、ファイルの署名にも使用できます。対称アルゴリズムでは、1 つのキーが暗号化に使用され、もう 1 つのキーが復号化に使用されます。 RSA暗号化通信を行う場合、公開鍵をクライアントに置き、秘密鍵をサーバーに置きます。

一般的に言えば
公開鍵と秘密鍵の生成
1.公钥加密,私钥解密2.私钥对文件进行签名,公钥对签名进行验证

  1. openSSL コマンドを使用して鍵を生成します

openssl req -x509 -out public_key.der -outform der -new -newkey rsa:1024 -keyout private_key.pem
プロンプトに従い、秘密キーのパスワード (後で使用します)、署名証明書の組織名、電子メール、および電子メールを入力します。その他の情報、および公開キー証明書ファイル public_key.der と秘密キー ファイル private_key.pem を含む生成されたファイル。

public_key.der ファイルは公開キーの暗号化と復号化のために iOS クライアントに配布するために使用されますが、private_key.pem ファイルは PHP で使用するためにサーバー側に残されます

openssl rsa -in private_key.pem -pubout -out public_key.pem
このコマンドは、入力された秘密鍵ファイルに基づいて pem 形式で公開鍵ファイルを生成します。これが、private_key がサーバー側に配置される理由でもあります。

サーバー側。 php コード (ThinkPHP フレームワーク、暗号化および復号化コードはフレームワーク関係とは直接関係ありません)

    <?php    /**     * Created by PhpStorm.     * User: and     * Date: 16/2/1     * Time: 10:14     */    namespace Home\Controller;    class RsaController extends CommenController {    //使用文本打开之前获取的private_key.pem可得如下        const PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----    MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAN2DTzqHsIiEw8bQ    R3MT9FpwVzet+kGQphJCFfY6A5u4gK6BuiVKqJpRroJlzg5yT3zy5tzowpSqIuMZ    8104ncih3uvKoNvvPhwjTy6mGHJHoKaGBlnK7oMXOmi50wVA8qvf++kZnxn9W7tM    YnCe6GSkQBS5KgythpIqPaqcaY1dAgMBAAECgYEAjTfqacEZvV8OxRABjQ76qDGY    mOm0cto51cgF4k0IAd21RAt2VdHr/T33yDAJFtKvdFQS9GD7s/VnemsP6K1wgMld    AvV2+KAPK2ZcCNTktLLBmOikJtBYQZGBnaAlxKQD2RFr+YJRCORxSQfOgGVxzch6    tgXC7VyQmddYBvaOEq0CQQD0dRHMxvn8iTa1x+Df4ghE3XZwyG8rDIpMehfAQdm/    hgf5Z1DX56DOG0LD99OMH5wE+C8CHdSP9F842cFJrZjTAkEA5/jlFcQU3vW/6fmk    XshHyaF40s9+5K84i/1EzTW/Wx08zZGql/WrTuQ8QllMAUDR6+kZvPLSPexA/8DS    e8xjDwJAObn7fhPurIfqd3q/y56gvUJe2bs7JTtM3UpnmWrzdJq9/1M6cAGuo30k    gwpe1lQQj8vbrfBFZckbQ12Im1F3KQJBAIBQCY+nnY/SyaxHfWc8S5E5cxbQ1bTz    Q0kT+Cm2sDlbC9X93CogJvkFgFuG/2a2Dyf6EVWVzzuXYkDVzNfTr3sCQQCdTK7v    I+C/aVcGFFYE0ZL5y3zxUtccBdhJNORb2fG5Oa7tqJH2bancuspeoArcpqElH7GQ    Mm9YArj1T6E10X0E    -----END PRIVATE KEY-----';        public function test() {    //此处为了验证,所以取出publick_key.pem中的public_key        $public_key = '-----BEGIN PUBLIC KEY-----    MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdg086h7CIhMPG0EdzE/RacFc3    rfpBkKYSQhX2OgObuICugbolSqiaUa6CZc4Ock988ubc6MKUqiLjGfNdOJ3Iod7r    yqDb7z4cI08uphhyR6CmhgZZyu6DFzpoudMFQPKr3/vpGZ8Z/Vu7TGJwnuhkpEAU    uSoMrYaSKj2qnGmNXQIDAQAB    -----END PUBLIC KEY-----';    //之前使用openssl生成private_key时填写的密码    $open_key = '123456';        $pi_key = openssl_pkey_get_private(self::PRIVATE_KEY,$open_key);//这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id        echo $pi_key,"\n";        $pu_key = openssl_pkey_get_public($public_key);//这个函数可用来判断公钥是否是可用的        echo $pu_key,"\n";        $data = "xiaohulu123";//原始数据        $encrypted = "";        $decrypted = "";        echo "source data:",$data,"\n";        echo "private key encrypt:\n";        openssl_public_encrypt($data,$encrypted,$pu_key);//公钥加密,私钥解密        $encrypted = base64_encode($encrypted);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的        echo "公钥加密后:",$encrypted,"\n";        openssl_private_decrypt(base64_decode($encrypted),$decrypted,$pi_key);//私钥加密的内容通过公钥可用解密出来        echo "私钥解密:",$decrypted,"\n";        echo "\n","---------------------------------------","\n";        //私钥对数据进行签名,公钥解密验证        $bicode = "";        $cdbicode = "";        openssl_private_encrypt($data, $bicode, $pi_key);        $bicode = base64_encode($bicode);        echo "私钥签名:",$bicode,"\n";        openssl_public_decrypt(base64_decode($bicode), $cdbicode, $pu_key);        echo "公钥验证签名:",$cdbicode,"\n";    }    }
resourceID を取得できない場合は、まず openssl 拡張機能が有効になっているかどうかを確認してから、 private_key がインデントなどを使用して非公開で追加されているかどうか。

=============

iOS は JSPatch を使用します

JSPatch スクリプトの実行権限は非常に高いです。送信プロセス中です。仲介者によって改ざんされると、セキュリティ上大きな問題が発生します。この事態を防ぐために、送信プロセス中に JS ファイルを RSA 署名で暗号化します。

サーバー:

JS コンテンツの MD5 値を計算します。
  1. RSA 秘密キーを使用して MD5 値を暗号化し、JS コンテンツとともにクライアントに送信します。
  2. クライアント:

暗号化されたデータを取得し、RSA 公開キーを使用して MD5 値を復号化します。
  1. 返された JS コンテンツの MD5 値のローカル計算。
  2. 上記の 2 つの MD5 値を比較し、等しい場合は検証に合格し、JS ファイルがローカルに保存されます。 RSA は非対称暗号化であるため、第三者は秘密キーなしでは対応する MD5 値を暗号化できないため、JS ファイルを偽造できず、送信プロセス中に JS ファイルが改ざんされる可能性がなくなります。
  3. サーバー側の php コード

iOS 側のコード

iOS のネイティブ暗号化と復号化はあまり役に立たないため、github でカプセル化された RSA 暗号化と復号化を使用します。方法は、RSA 暗号化と復号化をクリックしてダウンロードしてください
/*     * 加密一个字符串,返回RSA加密后的内容     * aString 需要加密的字符串     * return encrypted rsa加密后的字符串     */    public function enjscode($aString) {        $pi_key = openssl_pkey_get_private(self::PRIVATE_KEY);//这个函数可用来判断私钥是否是可用的,可用返回资源id Resource id        openssl_private_encrypt($aString, $encrypted, $pi_key);//私钥加密        $encrypted = base64_encode($encrypted);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的        return $encrypted;    }    //JS    public function jscode() {        //$headers = $this->verifyHeaders();        //验证header        //$this->verifyHeadersWithHeaders($headers);        $data['con'] = "defineClass('FindViewController',{viewDidLoad: function() {self.super().viewDidLoad();self.setTitle('发现哈哈');_selectedIndex = 0;self.initView();}})";        $data['isUpdate'] = 'true';       //首先计算js内容的md5值,再将md5值进行RSA加密        $data["ver"] = self::enjscode(md5($data['con']));        $data1['con'] = "require('UIAlertView');defineClass('CircleHotPageViewController',{tableView_didSelectRowAtIndexPath:function(tableView,indexPath){tableView.deselectRowAtIndexPath_animated(indexPath, YES);var alert = UIAlertView.alloc().initWithTitle_message_delegate_cancelButtonTitle_otherButtonTitles('只是提示而已', '测试JSPath!', null, '知道了', null, null);alert.show();}})";        $data1['isUpdate'] = 'true';        $data1["ver"] = self::enjscode(md5($data1['con']));        $this->json_out('200','0','',$da);    }

Import Security.framework
  1. public_key.pem の public_key を取り出します
3. DidFinishLaunchingWithOptions メソッドでネットワーク リクエストを作成し、ネットワークからコンテンツ データを取得します
#define rsa_public_key @"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDdg086h7CIhMPG0EdzE/RacFc3rfpBkKYSQhX2OgObuICugbolSqiaUa6CZc4Ock988ubc6MKUqiLjGfNdOJ3Iod7ryqDb7z4cI08uphhyR6CmhgZZyu6DFzpoudMFQPKr3/vpGZ8Z/Vu7TGJwnuhkpEAUuSoMrYaSKj2qnGmNXQIDAQAB"

4. applicationDid becomeActive メソッドで、js ファイルを読み取り、
    /*     *  获取内容为     *  con         js内容     *  isUpdate    是否更新(无用)     *  ver         验证内容,有con 计算md5,再进行rsa加密得来  ->  客户端首页解密得到con的md5值,将此md5值与获取的js内容的md5值进行比较     *           *  若值相等,则说明无篡改;否则,说明被篡改,放弃存储     */    - (void)upJSHandle:(NSDictionary *)response {    NSMutableString *jsString = [NSMutableString string];    for (NSDictionary *di in (NSArray *)response) {        NSString *js = di[@"con"];       //计算获取到的js内容的md5值        NSString *jsMd5 = [MiscTool md5:js];        //解密获取js内容的md5        NSString *cdMd5 = [RSA decryptString:di[@"ver"] publicKey:rsa_public_key];        NSLog(@"cd bicode = %@",cdMd5);        //校验        if (![jsMd5 isEqualToString:cdMd5]) {//经过校验,不相等,说明内容被篡改,直接返回不存储            NSLog(@"zz 内容被篡改!!!");            return;        }        [jsString appendString:js];        //将代码下载到本地,保存成文件Document/up.js, 各个方法之间使用 ***** 分隔符        [jsString appendString:@"*****"];        }        //获取保存js文件内容        NSString *jsPath = [self jsFilePath];        NSLog(@"js xx = 写入 %@",jsString);        //将jsString 进行aes对称加密        //jsString = [self aes:jsString].mutableCopy;        //NSLog(@"xx 加密后 = %@",jsString);        NSData *jsData = [jsString dataUsingEncoding:(NSUTF8StringEncoding)];        //写入文件        [jsData writeToFile:jsPath atomically:YES];        //执行        [self execUpJsWithJsArray:[self readJs]];    }

を実行します。ローカル ストレージ
    #pragma mark -- js 读取    - (NSArray *)readJs {        NSString *file = [self jsFilePath];        NSFileManager *fileManager = [NSFileManager defaultManager];        if(![fileManager fileExistsAtPath:file]) {//如果不存在            return @[];        }        NSString *jsString = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil];        //取出后,将jsString 解密        //jsString = [self cdAes:jsString];        //NSLog(@"xx 解密后 = %@",jsString);        NSArray *jsArray = [jsString componentsSeparatedByString:@"*****"];        return jsArray;    }    - (void)execUpJsWithJsArray:(NSArray *)jsArray {        if (jsArray.count == 0) {            return;        }        [JPEngine startEngine];        for (NSString *js in jsArray) {            if ([js isEqualToString:@""] || js == nil) {                continue;            }            NSLog(@"read js = %@",js);            [JPEngine evaluateScript:js];        }    }    - (void)applicationDidBecomeActive:(UIApplication *)application {    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.    //每次进入时执行js    [self execUpJsWithJsArray:[self readJs]];      }

ローカルに保存されたスクリプトが改ざんされる可能性ははるかに低く、ジェイルブレイクされたマシンでは危険が少しだけあります。このため、スクリプトをダウンロードしてローカルに保存した後に対称暗号化を実行できます。そして読み取られるたびに復号化します。

aes 暗号化と復号化

    /*     *  进行aes对称加密     */    - (NSString *)aes:(NSString *)aString {        NSString *biCode = [SecurityUtil encryptAESData:aString app_key:aesKey];        //NSLog(@"xx 加密: %@",st);        return biCode;    }    /*     *  对字符串进行aes解密     */    - (NSString *)cdAes:(NSString *)aString {        //NSData *EncryptData1 = [GTMBase64 decodeString:[SecurityUtil encryptAESData:string app_key:aesKey]]; // 解密前进行 GTMBase64 编码        NSData *EncryptData = [GTMBase64 decodeString:aString];        NSString *unCode = [SecurityUtil decryptAESData:EncryptData app_key:aesKey];        //NSLog(@"xx 解密:%@", string1);        return unCode;    }
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。