2020年10月26日月曜日

MODサイバーセキュリティ要員を募集中らいし

 MOD(防衛省)がサイバーセキュリティ要員の募集をかけてます。

https://www.mod.go.jp/js/saiyou/pdf/s20201007_01.pdf

確か、今年の2月ぐらいにも同じ募集があったような気がしますが、集まらなかったのかなぁ...

菅内閣になってから、デジタル移行が重要視されており、その絡みもあって単純にサイバーセキュリティ要員が不足しているから追加募集という風にも考えられますが、前回の募集と違ってお賃金の額が例示されている点が気になる。

募集条件は割と緩いです。

  • 正社員(or官公庁の正職員)として勤続合計13年以上
  • 年齢制限あり
  • IPAのITスキル標準レベル3以上
  • 犯罪歴や懲戒歴等なしの日本人

私は募集条件を満たしています。

というか、母数(条件を満たしている人数)は普通に多いと思います。

かなり興味があるのですが、今の仕事をちゃんとバトンタッチするなり終わらせるなりしてからじゃないと公務員にはなれないので中々悩ましい。公務員になると当然営利の副業はNGですが、営利じゃなくて無報酬であっても民間企業の手伝いはNGになる(憲法でそういう風に規定されている)ので難しい。

なお、お賃金はお安め(個人的にはこの点は全然問題なし)

ちなみに、この採用試験に合格できる人なら、民間でその気を出せば普通に倍以上稼げると思います。それでも尚、やりたいと思える=全体の奉仕者として働く熱意といった感じでしょうか。(もちろん、お賃金に限った話ではないですが。ただ、お賃金額を例示したということは前回募集ではその辺がネックになったのかな?などと邪推してしまう...防衛省職員のお賃金は法律で決まっているので、採用等級だけ示せば例示不要な筈で、前回募集でも「係長相当職員(行(一)3級)」と明示されていたので、載せる意味なんて無いのでは?と思うのですが...

転職を考えてた2013〜2014年頃、丁度警察でも似たような募集(サイバー犯罪の調査員とかだったかな?)があって心揺らぎましたが、当時も似たようなことで悩んで結局民間企業に転職しました。当時抱えていた悩みどころは解消済みなのですが、今はタイミングだけが合わない。中途半端に仕事を投げ出せば不可能ではないですが、まぁ、それは性格的に無理です。

つくづく、公務員とは縁が無いなぁ。(興味はあるのですが)

2020年10月23日金曜日

UIImagePickerControllerで許可を求められない件

 iOSアプリでフォトライブラリから画像を取得する方法として、

  1. UIImagePickerControllerを使用する方法
  2. PHPhotoLibraryを使用する方法
という2種類の方法があります。(※どちらもiOSが提供するAPIです)

違いとしては、前者(UIImagePickerController)はOSが提供するUIを利用するのに対して、後者(PHPhotoLibrary)はフォトライブラリからデータを参照する(UIを独自に実装する必要がある)という点にあります。

なので、UIImagePickerControllerの方が手軽に使えます。

UIImagePickerControllerは、iOS11から仕組みが大きく変わり、OSプロセスで写真を選択し、選択された写真をアプリプロセスへ返す形になりました。

iOS10以前のUIImagePickerControllerは、アプリプロセスからフォトライブラリにアクセスしていたので、フォトライブラリへアクセスしようとしたタイミングで以下のような確認が求められていました。

フォトライブラリのアクセス許可

しかし、iOS11以降では許可が不要になりました。

iOS11以降の場合、PHPhotoLibraryを使用しているアプリでのみフォトライブラリへのアクセス許可が求められます。

(セキュリティ的にどちらが安全か?)

仮に信頼できないアプリを利用する時、UIImagePickerController(許可不要)とPHPhotoLibrary(許可が必要)のどちらが安全でしょうか?

UIImagePickerControllerは、許可自体不要ですが、許可をしていない以上アプリが勝手にフォトライブラリをアクセスすることは出来ません。

一方、PHPhotoLibraryは必要なタイミングで許可を与えなければならず、許可を与えてしまった以上どのような目的でフォトライブラリにアクセスされるか分かりません。

なので、セキュリティ的にはUIImagePickerController(許可不要)の方が安全です。

セキュリティ意識が高い方は、iOS11以降ではフォトライブラリへのアクセス許可を求めてくるアプリに基本的に許可を与えないようにすることをオススメします。何が抜かれるか分からないですからね。必要に迫られて許可を与える場合は「写真を選択...」を選んで、アプリにアクセス権限を与えても良い写真のみ選ぶと良いです。(私は抜かれて困る写真は入っていないので割とホイホイとフルアクセス許可を与えてますが...これはこれで寂しい)

以下の記事で、「iOS11からUIImagePickerControllerで許可が求められなくなったので、PHPhotoLibraryで許可を求めるようにした(そうしないとリジェクトされるかも)」という内容が紹介されていたのですが、UIImagePickerControllerを使って許可を求めない分にはリジェクト対象にはなりません。(何故なら、アプリではフォトライブラリに直接アクセスしていないのでAppStoreのレビューガイドライン違反になりません)

https://qiita.com/Masataka-n/items/468a38379c3f3bf132ca

そもそも、PHPhotoLibraryで求める許可は、PHPhotoLibraryでフォトライブラリへアクセスするためのものです。フォトライブラリへのアクセス権限には「全部許可」「一部許可」「許可しない」の3種類が現在(iOS14では)ありますが、例えば「一部許可」した状態でUIImagePickerControllerを起動しても一部ではなく全部の写真が表示される「許可の矛盾状態」が起きます。ユーザ視点で見ても「許可していない写真が見えている」と不安になるのではないでしょうか。要するにUIImagePickerControllerを用いるためにPHPhotoLibraryでアクセス許可を求める実装はNGです。

PHPhotoLibraryでアクセス許可を求めるならPHPhotoLibraryでPHAssetsへアクセスする独自UIを作るべきです(・・・が、写真を選ぶだけなのにわざわざUIImagePickerControllerを使わずにアクセス許可を求めてくる方が、「このアプリはセキュリティ的に大丈夫なのだろうか?」と個人的には不安に思ってしまいます)


以下のフォーラムで、Appleフレームワークエンジニアが同じようなことを言っています。個人的には日本語でヒットする記事よりも、Appleフレームワークエンジニアの回答が全面的に正しいと思ったので、今回記事にしてみました。

https://developer.apple.com/forums/thread/653414

(Appleフレームワークエンジニアの回答を引用) 

UIImagePickerController runs out-of-process since iOS 11. There is no need to prompt for Photos Library access before showing the picker on iOS 11 and above, unless you really need to work with the selected PHAssets.


As outlined in this years session, there are some considerations for using the picker with Limited Library:


> The picker will still show the entire Photos Library and all photos and videos can be selected by the user. No matter what the users selects in the picker, the PHAssets you can access will not change.


There is no support to only show assets in the picker that you app has access to when in Limited Library mode. 

Please feel free to provide feedback and outline the use case where your app would need to further restrict the selection.

2020年10月18日日曜日

iOSサブスクリプション実装後に心臓に悪い日々を過ごさなくて済むために読んでおいた方が良い記事

 先日、本業でAppStoreサブスクリプションに対応したサービスをリリースしたのですが、クライアント側の実装に大きな問題があり、現在その対策版の審査待ちという状況です。初めて特急審査出してみました。既にサービス開始してしまっていることから、それだけでもかなり心臓に悪く、眠れぬ日々が続いております。

今後ほかの方が同じ轍を踏まなくて済むように、一体どのような問題が起こり、どのような対処をしたのか可能な限りなるべくわかり易く書き記しておこうと思います。


(AppStoreサブスクリプションの概要)

サブスクリプションを定期購読すると「レシート」と呼ばれるものが発行されます。アプリでこのレシート取得して、自前のサーバへ送信&検証することで、ユーザが購読者か否かを判定する...というのが、基本的なサブスクリプション実装方法です。(詳細はコチラを参照)


(今回発生した問題)

定期購読したユーザがアプリを再起動すると、定期購読中と判定されない不具合が発生しました。

つまり、買ったのに「買ってない」と判定されてしまう致命的なバグです。


(問題の原因)

アプリでレシートを取得するには、Bundle::appStoreReceiptURLというAPIを用いますが、どうもこのAPIがnilを返しているらしいことがサーバのログから判明しました。

不思議なことに暫く時間を置いてからリトライすれば、正しい値が返されます。

これと類似する現象が以下のStack Overflowで公開されていました:

https://stackoverflow.com/questions/20027322/appstorereceipturl-on-mainbundle-always-returns-nil

上記によると、

SKReceiptRefreshRequest *refreshReceiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:@{}];
refreshReceiptRequest.delegate = self;
[refreshReceiptRequest start];

という形でレシートをリフレッシュする必要があるとのことでした。

ただし、上記実装ではローカル変数(弱参照)でSKReceiptRefreshRequestインスタンスを保持しているので問題があります。

以下の記事にもありますが、SKReceiptRefreshRequestインスタンスは強参照(strong@propertyなど)で保持しなければなりません。

https://asmz.hatenablog.jp/entry/in-app-purchase-not-working-in-tvos

そこで、アプリ起動時(ログイン時)にSKReceiptRefreshRequestインスタンスをリクエスト中は強参照で保持しつつ、リクエストを出す形の修正をしてApple審査に提出しましたが、リジェクトされました。


(審査リジェクト原因)

リジェクト理由は、アプリ起動後にタップ(ログイン)したところハングアップした(ガイドライン2.1違反)とのことです。

以下のStack Overflowに書かれていますが、AppStoreのsandbox環境でSKReceiptRefreshRequest::startを発行すると、クレデンシャルの入力が要求され、それをキャンセルすると二度と応答が返らない(アプリを一度削除してから再インストールする必要がある)とのことです。

https://stackoverflow.com/questions/30114489/skreceiptrefreshrequest-not-working-the-second-time-it-is-called-after-a-cancel

上記のAnswerに、

The only solution is to present an alert, telling the user to remove and download your app again from the store and to not cancel the credential box when the app asks for the apple ID/password. 

翻訳: 唯一の解決策は、ユーザーにアラートを提示し、アプリを削除して再度ダウンロードするように指示することと、アプリがアップルID/パスワードを要求したときにクレデンシャルボックスをキャンセルしないように指示することです。

という、「そんなまさか!?」と思うようなことが書かれていますが、考えうる限りどうもそれが事実のようです。という訳で、Apple審査を通すため、SKReceiptRefreshRequest::startの裏でNSTimerをスケジュールして一定時間(60秒)応答が無かった場合は、「アプリを削除して再度ダウンロードするように指示することと、アプリがアップルID/パスワードを要求したときにクレデンシャルボックスをキャンセルしないように指示」する旨のアラートを表示するという、〇〇(自粛)のような修正を入れて審査再提出しました。


(何故テストしきれないのか)

根本的な原因は、sandbox版AppStoreと本番AppStoreの挙動に違いが多すぎることにあります。

本番AppStoreでテストするには、一度Apple審査を通す必要があります。

Apple審査を通せば「プロモコード」を発行することで、本番AppStoreの挙動をテストできるのでは?と思われるかもしれません(私もそう思っていた時期がありました)が、リリースしていないアプリの場合、プロモコードを発行してもアプリをダウンロードできないので、「ローンチ一発目はぶっつけ本番で一般ユーザと一緒にテストするしかない」という、非常にロックンロールな仕様になっております。

だからバグっていても仕方がない・・・とは言いませんが、テストせずにバグを全て取り除くのは困難です。

実は、今回の対策で本当に問題対策できているかという確証がまだ無いです(本番環境でテストできていないので当然ですよね)。なので、Apple審査(現在審査待ち)に合格したら、今度こそはプロモコードを使って事前テストしたいところです。できなければ、またロックンロールするしかないですね。(審査後にテストできてまた問題が見つかったら、また審査待ちで数日を要し、その数日間がまたハラハラドキドキになってしまいますが、「治ったよ」と宣言して治ってなかったというケースと比べればまだ安心・・・なのだろうか。連日の徹夜続きで既に思考が正常ではないかも)

心臓に悪い日々はまだまだ続きそうだ。

合理的ではないものを作りたい

ここ最近、実機版の東方VGSの開発が忙しくて、東方VGSの曲追加が滞っています。 東方VGS(実機版)のデザインを作りながら検討中。基本レトロUIベースですがシークバーはモダンに倣おうかな…とか pic.twitter.com/YOYprlDsYD — SUZUKI PLAN (...