ASP.NET MVCでControllerに対するIPアドレス制限
ちょっとASP.NET MVCのController単位でIPアドレス制限してみるテスト(・∀・)
とりあえずIPアドレスチェックするクラスをこんなカンジで。
// IPアドレスヘルパー public static class IPAddressHelper { // addressがsubnet/mask内か判定 public static bool IsAddressInSubnet(IPAddress address, IPAddress subnet, IPAddress mask) { byte[] addressBytes = address.GetAddressBytes(); byte[] maskBytes = mask.GetAddressBytes(); byte[] maskedAddressBytes = new byte[ addressBytes.Length ]; for( int i = 0; i < maskedAddressBytes.Length; ++i ) { maskedAddressBytes[ i ] = (byte)( addressBytes[ i ] & maskBytes[ i ] ); } IPAddress maskedAddress = new IPAddress( maskedAddressBytes ); return subnet.Equals( maskedAddress ); } // サブネットマスク取得 public static IPAddress GetMaskIpAddress(int cidr) { switch( cidr ) { case 8: return IPAddress.Parse( "255.0.0.0" ); .. case 32: return IPAddress.Parse( "255.255.255.255" ); default: return IPAddress.Parse( "255.255.255.255" ); } } }
去年、同じようなもののJava版を作りましたが、今回はネットからコピペ(´д`;)
そして、チェック用のIPアドレス一覧を保持するクラスをこんなカンジで。
これは、後述のIPFilterAttributeで毎回IPアドレス一覧を作るのを省略するためだけのもの。
// サブネット/マスクリストのキャッシュ public class IPFilter { // subnet/maskのペア private class AddressPair { public IPAddress Subnet; public IPAddress Mask; } // キャッシュ private static readonly Dictionary<string, IPFilter> filters = new Dictionary<string, IPFilter>(); // IPアドレス一覧 private readonly List<AddressPair> allowList = new List<AddressPair>(); // キャッシュ取得 public static IPFilter Get(string addresses) { lock( filters ) { IPFilter filter; if( !filters.TryGetValue( addresses, out filter ) ) { filter = new IPFilter( addresses.Split( ',' ) ); filters[ addresses ] = filter; } return filter; } } // IPアドレス一覧構築 public IPFilter(params string[] ipAddresses) { foreach( string ipAddress in ipAddresses ) { int cidr = 32; int find = ipAddress.IndexOf( '/' ); if( find != -1 ) { cidr = Convert.ToInt32( ipAddress.Substring( find + 1 ) ); } AddressPair address = new AddressPair(); address.Subnet = IPAddress.Parse( find == -1 ? ipAddress : ipAddress.Substring( 0, find ) ); address.Mask = IPAddressHelper.GetMaskIpAddress( cidr ); this.allowList.Add( address ); } } // 一覧からの存在チェック public bool IsExist(string ipAddress) { foreach( AddressPair address in allowList ) { if( IPAddressHelper.IsAddressInSubnet( IPAddress.Parse( ipAddress ), address.Subnet, address.Mask ) ) { return true; } } return false; } }
っで、ASP.NET MVCのフィルタをこんなカンジで(・ω・)
// IPアドレスフィルタ [AttributeUsage( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true )] public class IPFilterAttribute : FilterAttribute, IAuthorizationFilter { private IPFilter ipFilter; public IPFilterAttribute(string configKey) { string addresses = ConfigurationManager.AppSettings[ configKey ]; if( addresses != null ) { this.ipFilter = IPFilter.Get( addresses ); } } public void OnAuthorization(AuthorizationContext filterContext) { if( this.ipFilter != null ) { if( !this.ipFilter.IsExist( filterContext.HttpContext.Request.UserHostAddress ) ) { throw new HttpException( 403, "Forbidden" ); } } } }
そして使い方(・∀・)
[IPFilter( "allowIPAddress" )] public class RestrictController : Controller { ... }
// Web.config <configuration> <appSettings> <add key="allowIPAddress" value="10.0.0.0/8,127.0.0.1"/> </appSettings> ... </configuration>
これでIPアドレス制限できたかな(・∀・)?