Cordova で iOS9 App Transport Security を回避する

## App Transport Security(ATS) とは

Apple のサーバ側セキュリティ基準。
Apple 基準を満たしていない場合、サーバ接続できず、 `An SSL error has occurred and a secure connection to the server cannot be made.` みたいなエラーが出る。

* 参考
    * [[iOS 9] iOS 9 で追加された App Transport Security の概要 ｜ Developers.IO](http://dev.classmethod.jp/smartphone/iphone/ios-9-intro-ats/)
    * [接続先がATS (App Transport Security)に対応しているか、または例外の設定をnscurlコマンドで簡単に調べる - 24/7 twenty-four seven](http://blog.kishikawakatsumi.com/entry/2015/10/19/121257)

## 設定で回避

### hook を作成

設定で回避できるため、[Hooks Guide - Apache Cordova](https://cordova.apache.org/docs/en/5.1.1/guide/appdev/hooks/) を使い設定を追加する。
hook は Cordova で提供されている、特定のタイミングでコードを実行できる仕組み。
今回は after_prepare に shell を書いた。

#### project_root/hooks/after_prepare/ios9-transport-security.sh

```
#!/bin/bash

PLIST=platforms/ios/*/*-Info.plist

cat << EOF |
Add :NSAppTransportSecurity dict
Add :NSAppTransportSecurity:NSExceptionDomains dict
Add :NSAppTransportSecurity:NSExceptionDomains:dev.example.com dict
Add :NSAppTransportSecurity:NSExceptionDomains:dev.example.com:NSExceptionAllowsInsecureHTTPLoads bool YES
Add :NSAppTransportSecurity:NSExceptionDomains:dev.example.com:NSExceptionRequiresForwardSecrecy bool NO
Add :NSAppTransportSecurity:NSExceptionDomains:dev.example.com:NSExceptionMinimumTLSVersion string TLSv1.0
Add :NSAppTransportSecurity:NSExceptionDomains:production.example.com dict
Add :NSAppTransportSecurity:NSExceptionDomains:production.example.com:NSExceptionAllowsInsecureHTTPLoads bool YES
Add :NSAppTransportSecurity:NSExceptionDomains:production.example.com:NSExceptionRequiresForwardSecrecy bool NO
Add :NSAppTransportSecurity:NSExceptionDomains:production.example.com:NSExceptionMinimumTLSVersion string TLSv1.0
EOF
while read line
do
    /usr/libexec/PlistBuddy -c "$line" $PLIST
done

true
```

なお、 config.xml には 以下の whitelist を設定してある。

```
  <access origin="http://*.example.com"/>
  <access origin="https://*.example.com"/>
```

## cordova prepare 後の info.plist の結果


```
..略..
    <key>NSAppTransportSecurity</key>
    <dict>
      <key>NSExceptionDomains</key>
      <dict>
        <key>example.com</key>
        <dict>
          <key>NSIncludesSubdomains</key>
          <true/>
        </dict>
        <key>dev.example.com</key>
        <dict>
          <key>NSExceptionAllowsInsecureHTTPLoads</key>
          <true/>
          <key>NSExceptionMinimumTLSVersion</key>
          <string>TLSv1.0</string>
          <key>NSExceptionRequiresForwardSecrecy</key>
          <false/>
        </dict>
        <key>production.example.com</key>
        <dict>
          <key>NSExceptionAllowsInsecureHTTPLoads</key>
          <true/>
          <key>NSExceptionMinimumTLSVersion</key>
          <string>TLSv1.0</string>
          <key>NSExceptionRequiresForwardSecrecy</key>
          <false/>
        </dict>
      </dict>
    </dict>
..略..
```


## Plugin で回避もできる？

[leecrossley/cordova-plugin-transport-security](https://github.com/leecrossley/cordova-plugin-transport-security) という plugin も出ていて、 NSExceptionAllowsInsecureHTTPLoads だけだったらこれで設定できる。

ただし自分の場合は、特定の URL だけの設定をしたかったので、上記 Plugin ではダメだった。

## hook を作った理由

Plugin に NSExceptionDomains の設定を書くと、`access origin` と競合してしまうようで、 `access origin` が優先して上書きしてしまう？ような現象が起きた。
これでだいぶ時間がかかってしまった。

本来ならば Plugin に `<config-file target="*-Info.plist" parent="NSAppTransportSecurity">` を書くのが筋だと思う、ただそうするとうまくいかなかったので shell を書いた次第。