LoginSignup
2

More than 3 years have passed since last update.

Swift: ネットワークリクエスト(URLSession、Alamofire を使って)、‪ファイルのアップロード‬、SSL証明書の検証を行うためのコード

Last updated at Posted at 2020-05-30

この記事の内容

  • NSURLSessionAlamofire を使用してネットワーク POST もしくは GET リクエストを行う方法について説明します。
  • SSL Pinning (SSL証明書の検証を行うためのコード)

サンプルコードが提供されるので、このページをブックマークし、これらのコードをプロジェクトにすばやく追加できます。

どうやってテストをするのか?

アプリケーションがネットワークリクエストを成功させることができるかどうかをテストするためのデバッグオプションはたくさんあります。プロキシ、またはWebフックを使用できます。ここでは、無料のオンラインWebフックツール https://webhook.site/ を使用しました。

サイトにアクセスすると、Webフックリンクが表示されます。そのURLへのリクエストを行うことができ、そしてウェブサイトのインターフェイス上でリクエスト内容を見ることができます。

Alamofire

Alamofire はネットワーク用のオープンソースのフレームワークです。

Github Repo
インストールガイド

GET / POST

func sendRequestRequest() {

    // httpリクエストヘッダーを追加する
    let headers = [
        "Authorization":"Bearer ABCD-EFGH-123-456",
        "CatName":"NekoNohe",
    ]

    let httpHeaders = HTTPHeaders(headers)

    // リクエストを実行する

    AF.request("https://apple.com/", method: .get, headers: httpHeaders)
        .validate(statusCode: 200..<300)
        //.responseJSON { response in
        .responseString { response in

            switch response.result {

            case .success(let value):
                debugPrint("HTTP Response Body: \(response.data)")

            case .failure(let error):
                print(error.localizedDescription)
            }

    }

}

ファイルのアップロード (multipartFormData)

func requestWith(image: UIImage){

    let url = "https://webhook.site/xxxxxxxxxxxx"

    let headers: HTTPHeaders = [
        "Content-type": "multipart/form-data"
    ]

    guard let imageData = image.jpegData(compressionQuality: 1.0) else { return }

    AF.upload(multipartFormData: { (multipartFormData) in
        multipartFormData.append(imageData, withName: "image", fileName: "image.jpg", mimeType: "image/jpeg")
    }, to: url, method: .put, headers: headers).responseString { (response) in

        switch response.result {

        case .success(let result):
            print(result)

        case .failure(let error):
            print(error.localizedDescription)


        }

    }

}

上記の方式を示す引数は使用対象のウェブサイトが要求する方式に変更する必要があります。一部のウェブサイトでは、POST 方式が必要となる可能性があります。

SSL Pinning (証明書の検証)

SSLピン留めとは

クライアントからサーバーにネットワーク要求を行う場合、クライアントとサーバーの間に第三者が存在する可能性があります。そして、第三者がリクエストを傍受し、独自の証明書を使ってデータを変更する可能性があります。しかし、SSL証明書の有効性を検証し、それらが実際のサーバーに属していることを確認すると、そういった行為を防ぐことができます。

ウェブサイトのSSLサーバ証明書を取得する

Safariブラウザを開き、ウェブサイト(https://apple.com など)にアクセスします。

ロックアイコンをクリックし、ボタンをクリックすると詳細が表示されます。

image

次に、証明書をアイコンからファインダにドラッグします。

image

コード

まず、パブリック認証ファイルをプロジェクトに追加する。この例では、ファイル名は www.apple.com.cer だ。ファイルがプログラミングのターゲットにリンクされていることを確認すること。

Alamofire session を用意する。
var session: Session!

func getSecureSession() -> Session? {

    if let filePath = Bundle.main.path(forResource: "www.apple.com", ofType: "cer"),
        let data = try? Data(contentsOf: URL(fileURLWithPath: filePath)),
        let certificate = SecCertificateCreateWithData(nil, data as CFData) {

        let manager = ServerTrustManager(evaluators:
            [
                "www.apple.com": PinnedCertificatesTrustEvaluator(certificates: [certificate], acceptSelfSignedCertificates: false, performDefaultValidation: true, validateHost: true)
        ])
        let configuration = URLSessionConfiguration.af.default

        return Session(configuration: configuration, serverTrustManager: manager)

    }

    return nil

}

ここに、ドメイン名とポリシーをマッピングする辞書(ディクショナリ)がある。

"www.apple.com": PinnedCertificatesTrustEvaluator(certificates: [certificate], acceptSelfSignedCertificates: false, performDefaultValidation: true, validateHost: true)
リクエストする。
func sendRequestRequest() {

    guard let session = getSecureSession() else { return }
    self.session = session

    // Perform the request

    self.session.request("https://apple.com/", method: .get)
        .validate(statusCode: 200..<300)
        //.responseJSON { response in
        .responseString { response in

            switch response.result {

            case .success(let value):
                debugPrint("HTTP Response Body: \(response.data)")

            case .failure(let error):
                print(error.localizedDescription)
            }

    }

}

そうすると、接続しているドメインが www.apple.com なのであればリクエストが通る。

SSL証明を別のウェブサイトの証明書と置き換え、リクエストエラーが発生することを確認してみるといいだろう。

SSLサーバ証明書には有効期限があります。

アプリに保存されているSSLサーバ証明書は、たまに更新する必要があります。

NSURLSession

POST / GET

func sendRequest() {

    let sessionConfig = URLSessionConfiguration.default
    let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)

    //URLを設定する
    let urlString = "https://webhook.site/xxxxxxxxxxxx"
    guard let URL = URL(string: urlString) else { return }

    var request = URLRequest(url: URL)

    //リクエストの方式 `(GET, POST)` を設定する
    request.httpMethod = "GET"

    //OAuth 2 Bearer トークン
    request.addValue("Bearer ABCD-EFGH-123-456", forHTTPHeaderField: "Authorization")

    //httpリクエストヘッダーを追加する
    request.addValue("NekoNohe", forHTTPHeaderField: "CatName")
    request.addValue("token=NekoNeko", forHTTPHeaderField: "Cookie")

    //httpリクエストボディーを追加する
    let JSONdictionary : [String: Any] = [
                                          "name": "axel",
                                          "favorite_animal": "fox"
                                         ]

    if let postData = try? JSONSerialization.data(withJSONObject: JSONdictionary, options: []) {
        request.httpBody = postData
    }

    //データタスクを定義する
    let task = session.dataTask(with: request, completionHandler: { (data: Data?, response: URLResponse?, error: Error?) -> Void in
        if (error == nil),
            let httpResponse = response as? HTTPURLResponse {
            // リクエスト成功
            let statusCode = httpResponse.statusCode
            // TODO: コードをここに追加する
        }
        else {
            print(error?.localizedDescription)
        }
    })
    task.resume()
    session.finishTasksAndInvalidate()
}

その他の

私は以前に Twitter にコンテンツを投稿するための Swift & NSURLSession プログラムを書く方法について記事を書いています。こちらからお読みいただけます。


:relaxed: Twitter @MszPro

:sunny: 私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2