WebSurfer's Home

Filter by APML

IIS での IP アドレスによるアクセス制限

by WebSurfer 3. June 2025 10:17

自分のブログに良からぬことをする輩がいるので IP アドレスでアクセス制限をかけました。以下にどのように設定したかを備忘録として書いておきます。

IIS Manager が使える場合は、Microsoft のドキュメント「IP セキュリティ <ipSecurity>」および「IP セキュリティの追加 <add>」に従って設定すればよさそうです。

しかしながら、自分が使っているホスティングサービスでは IIS Manager は利用できず、ホスティングサービスが用意しているコントロールパネル上では GUI による操作ができません。なので、直接 web.config を編集してアクセス制限のための ipSecurity 要素を書き加えなければなりません。

自分の開発マシンは Windows 10 Pro 64-bit ですので IIS 10 と IIS Manager が使えます。それを使って GUI でアクセス制限のための ipSecurity 要素を作成できます。それを運用環境の web.config にコピーすればよさそうです。

注意:
自分の環境では ApplicationHost.config に <section name="ipSecurity" overrideModeDefault="Deny" /> という制約があって、下位のサイト/アプリケーションの web.config には ipSecurity 要素を設定できません。なので、自分の環境では 以下の IIS Manager を使っての操作では ipSecurity 要素は ApplicationHost.config に追加されます。ホスティングサービスの ApplicationHost.config にはそのような制約はなく、作成した ipSecurity 要素はサイト/アプリケーションの web.config にコピーできます。

デフォルトでは IIS 10 には IP セキュリティの機能は含まれません。機能を追加するには、 Windows 10 PC の場合、下の画像のように「Windows の機能の有効化または無効化」のダイアログで [IP セキュリティ] にチェックを入れて機能を有効化します。(Windows Server では [役割と機能の追加] で [IP and Domain Restriction] にチェックを入れて有効化します)

IP セキュリティの機能を追加

IP セキュリティの機能を追加すると、IIS Manager 上に「IP アドレスおよびドメインの制限」という機能が表示されるようになります。下の画像がそれです。

IP アドレスおよびドメインの制限

ローカルの適当なサイトまたはアプリケーションを選び「IP アドレスおよびドメインの制限」機能を開いて作業を行います。上の画像の例では、Default Web Site 下の MvcApp という名前のアプリケーションを選んでいます。そのアプリケーション用の ipSecurity 要素を追加します。

「IP アドレスおよびドメインの制限」のアイコンをダブルクリックして機能を開き、IIS Manager 上の「操作」ウィンドウの [拒否エントリの追加...] をクリックすると下のダイアログが表示されます。問題の IP アドレスは 185.208.8.76 でしたが、今回は 185.208.8.0 から 185.208.8.255 までの帯域をアクセス制限します。

拒否の制限規則の追加

[OK] ボタンをクリックすると下の画面が表示されるので、上の操作で追加した規則を選んで「操作」ウィンドウの [機能設定の編集...] をクリックします。

機能設定の編集

下の画像の「IP およびドメインの制限の編集」ダイアログが表示されますので、画像のように設定し [OK] ボタンをクリックします。

IP およびドメインの制限の編集

上の画像で[特定できないクライアントのアクセス(A):]は[許可](デフォルト) にします。[拒否]にすると制限した IP アドレス以外も拒否されてしまいます。

[拒否アクションの種類(D):]はドロップダウンの 4 項目の中から選べます。今回は[検出されていません](HTTP 404 Not Found 応答を返す) を選びました。

その他の項目についての説明は Microsoft のドキュメント「IIS 8.0 動的 IP アドレス制限」を見てください。

[OK] ボタンをクリックするとルールが作成され、ApplicationHost.config に以下の通り ipSecurity 要素が追加されているはずなので確認してください。(未検証ですが、ApplicationHost.config で ipSecurity の overrideModeDefault が Allow となっていれば当該サイト/アプリケーションの web.config に追加されると思われます)

<location path="Default Web Site/MvcApp">
  <system.webServer>
    <security>
      <ipSecurity denyAction="NotFound">
        <add ipAddress="185.208.8.0" 
             subnetMask="255.255.255.0" 
             allowed="false" />
      </ipSecurity>
    </security>
  </system.webServer>
</location>

上の ipSecurity 要素を web.config にコピーしました。その作業を行ったのが 2025/5/20 です。それ以来、この記事を書いた今日まで 2 週間は問題のアクセスはないです・・・が、アクセス制限の効果があったのか、問題の輩がアクセスをやめただけなのかは分かりません。前者に期待したいですが。(笑)

Tags: , ,

Windows Server

GeoCoordinateWatcher で緯度経度を取得

by WebSurfer 24. May 2025 19:13

.NET Framework 4.8/4.8.1 の GeoCoordinateWatcher クラスを使っての緯度経度データ取得について調べたことを備忘録として書いておきます。

Microsoft のドキュメント GeoCoordinateWatcher class の Remarks に書いてありますが、GeoCoordinateWatcher は位置プロバイダから座標データを取得して位置情報を提供するそうです。

位置プロバイダには GPS, Wi-Fi triangulation, cell phone tower triangulation などがあるそうです。cell phone tower triangulation は関係なさそうに思いましたが、ノート PC にはモバイルルーターを使わず直接携帯データネットワーク経由でインターネットにアクセスできるものがあって、そのような PC に搭載されているのかもしれません。(未確認&想像です)

(Microsoft 位置情報サービスは IP アドレスも位置情報を得るための手段の一つとして使うそうですが GeoCoordinateWatcher クラスが使うかどうかは不明です)

複数の位置プロバイダが搭載されている場合は優先付けがされますが、その優先順序は状況に応じて変わり、例えば GPS の電波が届かない場所に移動した場合は Wi-Fi triangulation プロバイダが使われるそうです。

それらのプロバイダのいずれも使えない場合、Windows OS の「既定の場所」から情報を取得できます。Windows 10 の場合[設定]⇒[プライバシー]⇒[位置情報]と進み、下の画像の[規定値に設定]ボタンをクリックして表示される画面で設定します。

既定の場所

ちなみに自分の Windows 10 ノート PC には Wi-Fi しか搭載されていませんので、GeoCoordinateWatcher クラスが使う位置プロバイダは Wi-Fi triangulation のみということになります。

なので、自分が検証できるのは Wi-Fi triangulation プロバイダを使った場合と、Wi-Fi をオフにして「既定の場所」の情報を使った場合だけですが、実際に GeoCoordinateWatcher クラスを使ったコンソールアプリを作って試してみました。アプリのコードはこの記事の下の方に載せておきます。

まず「既定の場所」を設定します。下の画像は[規定値に設定]ボタンをクリックして表示される画面で既定の位置を設定したところです。(Wi-Fi と違う結果になるのがすぐ分かるよう今回の検証では皇居に設定しています)

既定の位置

Wi-Fi をオンにした状態でアプリを走らせたコンソール出力は以下の通りとなりました。(緯度経度は自宅の位置になるので小数点以下を xxxx で隠しています)

Permission: Unknown, Status: NoData
Permission: Granted, Status: Ready
Lat: 35.xxxxxxxxxxxxx, Long: 139.xxxxxxxxxxx

アプリを走らせるたびに計測を行うようで結果は毎回微妙に異なりますが、Google Map に緯度経度を入力して表示されたポイントを見ると計測ごとの差は 10m もありませんでした。

自宅(PC が置いてある場所)の周りに適切な Wi-Fi サービス提供者のアクセスポイントが複数存在するということが精度に影響するのでしょうが、自宅の環境ですとかなり正確に Google Map 上で自宅の位置が特定できてしまいました。悪用されるとかなりヤバそうです。(汗)

ちなみに triangulation は三角測量という意味です。自宅(PC が置いてある場所)の近くに存在する複数の Wi-Fi サービス提供者のアクセスポイントを、PC に搭載された Wi-Fi triangulation プロバイダがスキャンしてその位置を知るためのデータ (MAC アドレスという記事を見ましたが真偽不明) と電波強度を取得し、電波強度からアクセスポイントとの距離を計算し、三角測量により PC の位置を特定するというプロセスだそうです。

Wi-Fi triangulation

そのプロセスの過程でアクセスポイントの位置情報(緯度経度とか)が必要になります。もし仮に、スキャンして得たデータがアクセスポイントの MAC アドレスだとすると、MAC アドレスとアクセスポイントの緯度経度がデータベースに登録してあって、プロバイダはアクセスポイントの緯度経度を得るためにそのデータベースに照会すると言った操作が必要になるはずです。しかし、そのデータベースというのは何で、どこにあって、どのように位置情報を得ているのかは調べても分かりませんでした。

また、自分が試した限りですが、ネットに接続されているか否かは関係なく Wi-Fi がオンになっていれば正確な緯度経度データを取得できました。その時には外部のデータベースにはアクセスできないはずで、どのようにアクセスポイントの位置情報を得たのかは謎です。Windows の位置情報サービスとプライバシーの [場所の履歴] によると過去に取得した位置情報が一定時間 (Windows 10 では 24 時間) ローカルストレージに保存されるそうなので、そこから取得しているのかもしれません。(未検証、未確認です)

次に、Wi-Fi をオフにしてアプリを走らせるとコンソール出力は以下の通りとなります。下の Lat, Long の値を Google Map に入力して表示される場所を見ると「既定の場所」に設定した通り皇居となってました。

Permission: Unknown, Status: NoData
Permission: Granted, Status: Ready
Lat: 35.6839239255279, Long: 139.750550645143

以下に自分が検証に使ったサンプルコードを載せておきます。

using System;
using System.Device.Location;

namespace GeoCoordinateWatcherSample
{
    internal class Program
    {
        static void Main(string[] args)
        {
            GetLocationProperty2();
        }

        static void GetLocationProperty2()
        {
            GeoCoordinateWatcher geoWatcher = new GeoCoordinateWatcher();
            Console.WriteLine($"Permission: {geoWatcher.Permission}, " +
                              $"Status: {geoWatcher.Status}");

            geoWatcher.Start();

            // geoWatcher.Position を取得する時点で Status がまだ NoData
            // の場合は位置情報は取得できないので Ready になるまで待つ。
            // geoWatcher.Permission != GeoPositionPermission.Denied も
            // while の条件に入れないと、位置情報の取得が有効になってな
            // い場合は無限ループに陥るので注意
            while ((geoWatcher.Status != GeoPositionStatus.Ready) &&
                (geoWatcher.Permission != GeoPositionPermission.Denied))
            {
                System.Threading.Thread.Sleep(100);
            }

            if (geoWatcher.Permission == GeoPositionPermission.Denied)
            {
                Console.WriteLine($"Permission: {geoWatcher.Permission}, " +
                                  $"Status: {geoWatcher.Status}");
            }
            else
            {
                Console.WriteLine($"Permission: {geoWatcher.Permission}, " +
                                  $"Status: {geoWatcher.Status}");
                GeoCoordinate coord = geoWatcher.Position.Location;

                if (coord.IsUnknown != true)
                {
                    Console.WriteLine("Lat: {0}, Long: {1}",
                        coord.Latitude,
                        coord.Longitude);
                }
                else
                {
                    Console.WriteLine("Unknown latitude and longitude.");
                }
            }
        }
    }
}

Microsoft のドキュメント GeoCoordinateWatcher Class のサンプルコードはそのままでは動かないので注意してください。(環境によっては動くこともあるようですが)

動かない理由は、GeoCoordinateWatcher.TryStart メソッドでデータの取得が始まり即 true が返されますが、その時点では GeoCoordinateWatcher.Status はまだ NoData だからです。緯度経度データを取得するには TryStart メソッド実行後 Status が Ready になるまで待つ必要があります。

Tags: , ,

.NET Framework

System.Drawing 名前空間のグラフィックス機能

by WebSurfer 14. May 2025 14:45

.NET Framework ではない .NET 8.0 とか .NET 9.0 などでは Windows OS の GDI+ に依存する System.Drawing 名前空間のグラフィックス機能は Visual Studio のテンプレートで作るプロジェクトには含まれてないと思っていたのですが、Windows Forms アプリの場合は例外のようです。そのことを備忘録として書いておきます。

アプリの実行結果

そもそも Windows Forms は Windows API(GDI/GDI+)をマネージコードでラップし、Windows のユーザーインターフェイス要素へのアクセスを提供するアプリケーションフレームワークということなので、System.Drawing 名前空間のグラフィックス機能が使えないということはあり得ず、特別な配慮がされているようです。

下は Visual Studio 2022 のテンプレートを使ってターゲットフレームワーク .NET 9.0 で作成した Windows Forms アプリのプロジェクトのサンプルコードです。

using ClassLibrary;

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        PictureBox pictureBox1 = new();
        PictureBox pictureBox2 = new();
        Class1 classLibrary = new();

        public Form1()
        {
            InitializeComponent();

            pictureBox1.Size = new Size(210, 110);
            this.Controls.Add(pictureBox1);
            pictureBox1.Image = CreateBitmap();

            pictureBox2.Size = new Size(210, 110);
            pictureBox2.Location = new Point(0, 120);
            this.Controls.Add(pictureBox2); ;
            pictureBox2.Image = classLibrary.CreateBitmapAtRuntime();
        }

        // WinForms は Windows API(GDI/GDI+)をマネージコードでラップし、
        // Windows のユーザーインターフェイス要素へのアクセスを提供するアプリ
        // ケーションフレームワーク・・・ということなので、System.Drawing
        // 名前空間のグラフィックス機能はデフォルトで使える設定になり、以下の
        // コードは問題なく動く。NuGet の System.Drawing.Common は不要。
        public Bitmap CreateBitmap()
        {
            Bitmap flag = new(200, 100);
            Graphics flagGraphics = Graphics.FromImage(flag);
            int blue = 0;
            int white = 11;
            while (white <= 100)
            {
                flagGraphics.FillRectangle(Brushes.Blue, 0, blue, 200, 10);
                flagGraphics.FillRectangle(Brushes.White, 0, white, 200, 10);
                blue += 20;
                white += 20;
            }
            return flag;
        }
    }
}

上のコードの CreateBitmap メソッドで使っている System.Drawing 名前空間の Bitmap, Graphics, Brushes クラスはデフォルトで使える設定になっており、期待通り青白の横線が描画された Bitmap が生成されます。 この記事の一番上の画像の青白の旗が CreateBitmap メソッドで生成された Bitmap を PictureBox に表示したものです。

では、同じソリューションの中にクラスライブラリのプロジェクトを追加し、そこで上と同様に Bitmap, Graphics, Brushes クラスを使ったらどうなるでしょう?

クラスライブラリ

その場合、Bitmap, Graphics, Brushes クラスを利用するためには、クラスライブラリのプロジェクトに NuGet パッケージ System.Drawing.Common をインストールする必要があります。

NuGet パッケージ System.Drawing.Common

さらに、Visual Studio でプロジェクトのプロパティを開いて、Target OS を Windows に設定しないと警告 CA1416 が出ます。(#pragma warning disable CA1416 を追記して警告を抑制することもできますが)

Target OS を Windows に設定

クラスライブラリのコードも以下に参考に載せておきます。上の Form1 のコードでは、下のクラスライブラリを使って取得した Bitmap を PictureBox2 に表示しています。一番上の画像の赤白の旗がそれです。


namespace ClassLibrary
{
    public class Class1
    {
        public Bitmap CreateBitmapAtRuntime()
        {
            Bitmap flag = new(200, 100);
            Graphics flagGraphics = Graphics.FromImage(flag);
            int red = 0;
            int white = 11;
            while (white <= 100)
            {
                flagGraphics.FillRectangle(Brushes.Red, 0, red, 200, 10);
                flagGraphics.FillRectangle(Brushes.White, 0, white, 200, 10);
                red += 20;
                white += 20;
            }
            return flag;
        }
    }
}

Tags: , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。ブログ2はそれ以外の日々の出来事などのトピックスになっています。

Calendar

<<  June 2025  >>
MoTuWeThFrSaSu
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

View posts in large calendar