For security considerations, almost every dynamic website hasIPAddress shielding function. Many tutorials on this function are stored and verified using strings.IPAddress, I think this is not scientific, and I am trying to find the best design scheme.
"IPThe address length is32Bit, divided4Segment, each segment8In decimal format. The range of digits in each segment is0~255, Segments and segments are separated by periods ."
From this we understand that,IPThe address is actually32A positive integer inC #Available inUintType,SqlserverThere seems to be no corresponding type in the database; instead, the database supportsIntType, it will overflow; so we make a compromise: UseLong(Bigint)Type.
Tip:
IntValue Range:-2,147,483,648.To 2,147,483,647
UintValue Range: 0To 4,294,967,295
LongValue Range:-9,223,372,036,854,775,808.To 9,223,372,036,854,775,807
So howIPWhat if the address is converted into an integer? We can see thatIPaddressClass has a"[Rejected]"Instance PropertiesAddress, This attribute can indeed returnLongValue, but test the data:
"127.0.0.1"-> 16777343
"127.0.0.2"-> 33554559
It is indeed necessary to make it "reject". Such an integer is meaningless for us, and we cannot compare the input using this method.IPBetween twoIPBetween values.
Then, we will passIPaddressClassGetaddressbytes ()Instance method acquisitionIPOf4And then combine them into an integer. The following describes the extension method:
/// <Summary>
///SetIPConvert the address to an integer
/// </Summary>
/// <Returns>Integer</Returns>
Public StaticLong Convert to integer(ThisIPaddressIP)
{
IntX= 3;
LongO= 0;
Foreach(ByteFInIP.Getaddressbytes ())
{
O+ =(Long) F< 8 *X--;
}
ReturnO;
}
You can use this extension method as follows:
IPaddress. Parse ("127.0.0.1").Convert to integer()
There is also an extension method for Inverse conversion, which is usedLongTransfer backIPaddress:
/// <Summary>
///Convert integerIPAddress
/// </Summary>
/// <Returns>IPAddress</Returns>
Public StaticIPaddress ConvertIPAddress(ThisLongL)
{
VaRB= New Byte[4];
For(IntI= 0; I< 4; I++)
{
B [3 -I]=(Byte) (L> 8 *I& 255);
}
Return New IPaddress(B );
}
In this way, we can obtain correct and meaningful integers through calculation:
"127.0.0.1"-> 2130706433
"127.0.0.2"-> 2130706434
OKThe core of the solution has been established. The design is as follows:SqlserverData Table:
After this design, it will start and end at the time of addition.IPConvert addressLongType and save it, and specify an expiration time.
During verification, you only need to obtain all the entries that have not expired and compare the inputIPWhether the address is between the start value and the end value.
In the past, when using string storage and verification, either a preciseIPOr block one or two segments.IP, Such as"192. 168 .*.*", To block"192.168.1.200"To"192.168.4.64BetweenIPIt will be very troublesome;
In this way, we can easily implement:"192.168.1.200"Stored in the database is"3232235976","192.168.4.64"In the database,"3232236608Even with the naked eye, you can quickly determine whether the incoming addresses are between them, not to mention computer queries.
The following table is generated:EDMModel:
AddIPBlocked recordCode:
/// <Summary>
///Add a newIPBlocked Area
/// </Summary>
/// <Param name = "ipStart value of a CIDR Block">StartIP, Such61.51.200.0</Param>
/// <Param name = "ipSegment termination value">TerminationIP, Such61.51.255.255</Param>
/// <Param name ="Expiration time">Blocking deadline</Param>
/// <Returns>IDNo.</Returns>
Public StaticGuid Add(String IPStart value of a CIDR Block,String IPSegment termination value,DatetimeExpiration time)
{
VaRID= Guid.Newguid ();
VaRSIP= IPaddress.Parse (IPStart value of a CIDR Block).Convert to integer();
VaREIP= IPaddress.Parse (IPSegment termination value).Convert to integer();
Using(VaRC= New Sitemainentities())
{
//Check whether the sameIPShield records
VaRA=C.IPAddress shielding.Where (F=> F.Start value of a CIDR Block = Sip& F.Segment termination value = EIP );
//If yes, update the expiration time.
If(.Count ()>0)
{
VaRL=A.First ();
If(L.Expiration time <Expiration time) L.Expiration time =Expiration time;
}
//If the record does not exist, a new shield record is added.
ElseC.AddtoipAddress shielding(NewIPAddress shielding{ID= ID,Expiration time =Expiration time,Start value of a CIDR Block = Sip,Segment termination value = EIP });
C.Savechanges ();
}
ReturnID;
}
Detection specifiedIPCode indicating whether the address is blocked:
/// <Summary>
///Detection specifiedIPWhether the address is blocked
/// </Summary>
/// <Param name = "ipAddress">TheIPAddress</Param>
/// <Returns>Is it blocked?IP</Returns>
Public StaticBool Check if it is blocked(String IPAddress)
{
VaRIP= IPaddress.Parse (IPAddress).Convert to integer();
Using(VaRC= New Sitemainentities())
{
ReturnC.IPAddress shielding.Count (F=> F.Expiration time >Datetime.Now&&IP> =F.Start value of a CIDR Block & IP<= F.Segment termination value)>0;
}
}
This scheme is much more elegant than the previous string verification scheme and can improve the efficiency of database query. We recommend that you use this scheme in future website development.