0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Xamarin.FormsでのAzure SignalRのセキュリティにおける注意点

Last updated at Posted at 2020-11-18

以下の問題が発生していましたが解決したので記録しておきます。
同じような問題を抱える開発者もいると思うので参考になれば幸いです。

問題

SignalRの接続の際に以下のエラーが発生する場合がある。

The remote server returned an error: (429) Too Many Requests.

このエラーは不定期で発生し、エラーが発生しない場合もある。

Azure Functionsのログストリームで確認すると明らかに不自然な挙動がある。

AzureLogStream
Executing 'Negotiate' (Reason='This function was programmatically called via the host APIs.', Id=ユニークid1)
Executed 'Negotiate' (Succeeded, Id=ユニークid1, Duration=5ms)
Executing 'Negotiate' (Reason='This function was programmatically called via the host APIs.', Id=ユニークid2)
Executed 'Negotiate' (Succeeded, Id=ユニークid2, Duration=5ms)
Executing 'Negotiate' (Reason='This function was programmatically called via the host APIs.', ユニークid3)
Executed 'Negotiate' (Succeeded, Id=ユニークid3, Duration=5ms)

上記のエラーが出る場合はこのようなアクセスが集中している状態です。

典型的なDoS攻撃に見えます。

前提

Xamarin.FormsでのSignalRの実装は以下のサンプルを利用しています。
https://docs.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/webservices-azuresignalr/

サンプルは以下の構成になっています。

ChatServerではMicrosoft.Azure.WebJobs.Extensions.SignalRS 1.1.0を使用。
NegotiateのAuthorizationLevelがAnonymousになっている。

Negotiate.cs
    public static class Negotiate
    {
        [FunctionName("Negotiate")]
        public static SignalRConnectionInfo GetSignalRInfo(
            [HttpTrigger(AuthorizationLevel.Anonymous,"get",Route = "negotiate")]
            HttpRequest req,
            [SignalRConnectionInfo(HubName = "simplechat")]
            SignalRConnectionInfo connectionInfo)
        {
            return connectionInfo;
        }
    }

ChatClient側Negotiateの呼び出し

SignalRService.cs
        public async Task ConnectAsync()
        {
                //(略)
                string negotiateJson = await client.GetStringAsync($"{Constants.HostName}/api/negotiate");
                NegotiateInfo negotiate = JsonConvert.DeserializeObject<NegotiateInfo>(negotiateJson);

                HubConnection connection = new HubConnectionBuilder()
                    .AddNewtonsoftJsonProtocol()
                    .WithUrl(negotiate.Url, options =>
                    {
                        options.AccessTokenProvider = async () => negotiate.AccessToken;
                    })
                    .Build();
                //(略)
        }

解決策

Azure Functionsのセキュリティには関数キー(アプリキーとは別なので注意)というものがあります。
https://docs.microsoft.com/ja-jp/azure/azure-functions/security-concepts
関数のアクセス キーあたりを参照

それを踏まえて実装

ChatServer側はAuthorizationLevel.AnonymousをFunctionに変更するだけ(Talkも修正してください)

Negotiate.cs
    public static class Negotiate
    {
        [FunctionName("Negotiate")]
        public static SignalRConnectionInfo GetSignalRInfo(
            [HttpTrigger(AuthorizationLevel.Function,"get",Route = "negotiate")]
            HttpRequest req,
            [SignalRConnectionInfo(HubName = "simplechat")]
            SignalRConnectionInfo connectionInfo)
        {
            return connectionInfo;
        }
    }

ChatClient側はAzure Function Keyを設定します(埋め込みはよくないので検討してください)

SignalRService.cs
        public async Task ConnectAsync()
        {
                //(略)
                string negotiateJson = await client.GetStringAsync($"{Constants.HostName}/api/negotiate?code={AZURE_FUNCTION_NEGOTIATE_KEY}");
                NegotiateInfo negotiate = JsonConvert.DeserializeObject<NegotiateInfo>(negotiateJson);

                HubConnection connection = new HubConnectionBuilder()
                    .AddNewtonsoftJsonProtocol()
                    .WithUrl(negotiate.Url, options =>
                    {
                        options.AccessTokenProvider = async () => negotiate.AccessToken;
                    })
                    .Build();
                //(略)
        }

結論

もともとサンプルを基に実装している段階でセキュアキーの設定がないことに???となっていたのですが、
参考にできるページがみつからなくて四苦八苦していました。
とはいえわかってしまえば当たり前な実装手法です。

今回は内部テストの段階で判明したので大事には至りませんでしたが、そのまま稼働させてたらと思うとぞっとします。

本当はサンプル内にコメントがほしいですがGitHubにissueできる英語力はないので他の人にお任せしますw

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?