Skip to content

Commit f2b938b

Browse files
committed
More reliable recognition of anonymous visitors (bad bots, cookie-rejecting morons etc.)
1 parent a91cadc commit f2b938b

File tree

16 files changed

+348
-225
lines changed

16 files changed

+348
-225
lines changed

src/Libraries/SmartStore.Core/IWebHelper.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,21 @@ public partial interface IWebHelper
1313
/// <returns>URL referrer</returns>
1414
string GetUrlReferrer();
1515

16-
/// <summary>
17-
/// Get context IP address
18-
/// </summary>
19-
/// <returns>URL referrer</returns>
20-
string GetCurrentIpAddress();
16+
/// <summary>
17+
/// Gets a unique client identifier
18+
/// </summary>
19+
/// <returns>A unique identifier</returns>
20+
/// <remarks>
21+
/// The client identifier is a hashed combination of client ip address and user agent.
22+
/// This method returns <c>null</c> if IP or user agent (or both) cannot be determined.
23+
/// </remarks>
24+
string GetClientIdent();
25+
26+
/// <summary>
27+
/// Get context IP address
28+
/// </summary>
29+
/// <returns>URL referrer</returns>
30+
string GetCurrentIpAddress();
2131

2232
/// <summary>
2333
/// Gets this page name

src/Libraries/SmartStore.Core/IWorkContext.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,5 @@ public interface IWorkContext
5959
/// Gets or sets a value indicating whether we're in admin area
6060
/// </summary>
6161
bool IsAdmin { get; set; }
62-
63-
///// <summary>
64-
///// Gets a value indicating whether we're in the public shop
65-
///// </summary>
66-
//bool IsPublic { get; }
67-
}
62+
}
6863
}

src/Libraries/SmartStore.Core/WebHelper.cs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public partial class WebHelper : IWebHelper
3434
private bool? _isCurrentConnectionSecured;
3535
private string _storeHost;
3636
private string _storeHostSsl;
37+
private string _ipAddress;
3738
private bool? _appPathPossiblyAppended;
3839
private bool? _appPathPossiblyAppendedSsl;
3940

@@ -56,17 +57,71 @@ public virtual string GetUrlReferrer()
5657
return referrerUrl;
5758
}
5859

60+
public virtual string GetClientIdent()
61+
{
62+
var ipAddress = this.GetCurrentIpAddress();
63+
var userAgent = _httpContext.Request != null ? _httpContext.Request.UserAgent : string.Empty;
64+
65+
if (ipAddress.HasValue() && userAgent.HasValue())
66+
{
67+
return (ipAddress + userAgent).GetHashCode().ToString();
68+
}
69+
70+
return null;
71+
}
72+
5973
public virtual string GetCurrentIpAddress()
6074
{
75+
if (_ipAddress != null)
76+
{
77+
return _ipAddress;
78+
}
79+
80+
if (_httpContext == null && _httpContext.Request == null)
81+
{
82+
return string.Empty;
83+
}
84+
85+
var vars = _httpContext.Request.ServerVariables;
86+
87+
var keysToCheck = new string[]
88+
{
89+
"HTTP_CLIENT_IP",
90+
"HTTP_X_FORWARDED_FOR",
91+
"HTTP_X_FORWARDED",
92+
"HTTP_X_CLUSTER_CLIENT_IP",
93+
"HTTP_FORWARDED_FOR",
94+
"HTTP_FORWARDED",
95+
"REMOTE_ADDR",
96+
"HTTP_CF_CONNECTING_IP"
97+
};
98+
6199
string result = null;
62100

63-
if (_httpContext != null && _httpContext.Request != null)
64-
result = _httpContext.Request.UserHostAddress;
101+
foreach (var key in keysToCheck)
102+
{
103+
var ipString = vars[key];
104+
if (ipString.HasValue())
105+
{
106+
var arrStrings = ipString.Split(',');
107+
// Take the last entry
108+
ipString = arrStrings[arrStrings.Length - 1].Trim();
109+
110+
IPAddress address;
111+
if (IPAddress.TryParse(ipString, out address))
112+
{
113+
result = ipString;
114+
break;
115+
}
116+
}
117+
}
65118

66119
if (result == "::1")
120+
{
67121
result = "127.0.0.1";
122+
}
68123

69-
return result.EmptyNull();
124+
return (_ipAddress = result.EmptyNull());
70125
}
71126

72127
public virtual string GetThisPageUrl(bool includeQueryString)

src/Libraries/SmartStore.Services/Authentication/FormsAuthenticationService.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ namespace SmartStore.Services.Authentication
1212
/// </summary>
1313
public partial class FormsAuthenticationService : IAuthenticationService
1414
{
15-
private readonly HttpContextBase _httpContext;
15+
private readonly HttpContextBase _httpContext;
1616
private readonly ICustomerService _customerService;
1717
private readonly CustomerSettings _customerSettings;
1818
private readonly TimeSpan _expirationTimeSpan;
@@ -33,7 +33,6 @@ public FormsAuthenticationService(HttpContextBase httpContext, ICustomerService
3333
this._expirationTimeSpan = FormsAuthentication.Timeout;
3434
}
3535

36-
3736
public virtual void SignIn(Customer customer, bool createPersistentCookie)
3837
{
3938
var now = DateTime.UtcNow.ToLocalTime();
@@ -95,6 +94,21 @@ public virtual Customer GetAuthenticatedCustomer()
9594

9695
if (customer != null && customer.Active && !customer.Deleted && customer.IsRegistered())
9796
{
97+
if (customer.LastLoginDateUtc == null)
98+
{
99+
try
100+
{
101+
// This is most probably the very first "login" after registering. Delete the
102+
// ASP.NET anonymous id cookie so that a new guest account can be created
103+
// upon signing out.
104+
System.Web.Security.AnonymousIdentificationModule.ClearAnonymousIdentifier();
105+
}
106+
finally
107+
{
108+
customer.LastLoginDateUtc = DateTime.UtcNow;
109+
_customerService.UpdateCustomer(customer);
110+
}
111+
}
98112
_cachedCustomer = customer;
99113
}
100114

@@ -117,5 +131,5 @@ public virtual Customer GetAuthenticatedCustomerFromTicket(FormsAuthenticationTi
117131

118132
return customer;
119133
}
120-
}
134+
}
121135
}

src/Libraries/SmartStore.Services/Common/UAParserUserAgent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,8 @@ public virtual bool IsBot
205205
{
206206
if (!_isBot.HasValue)
207207
{
208-
_isBot = _httpContext.Request.Browser.Crawler || this.Device.IsBot || this.UserAgent.IsBot;
208+
// empty useragent > bad bot!
209+
_isBot = this.RawValue.IsEmpty() || _httpContext.Request.Browser.Crawler || this.Device.IsBot || this.UserAgent.IsBot;
209210
}
210211
return _isBot.Value;
211212
}

src/Libraries/SmartStore.Services/Customers/CustomerExtentions.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public static bool IsBackgroundTaskAccount(this Customer customer)
5353
}
5454

5555
/// <summary>
56-
/// Gets a value indicating whether customer a search engine
56+
/// Gets a value indicating whether customer is a search engine
5757
/// </summary>
5858
/// <param name="customer">Customer</param>
5959
/// <returns>Result</returns>
@@ -84,13 +84,13 @@ public static bool IsPdfConverter(this Customer customer)
8484
return result;
8585
}
8686

87-
/// <summary>
88-
/// Gets a value indicating whether customer is administrator
89-
/// </summary>
90-
/// <param name="customer">Customer</param>
91-
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
92-
/// <returns>Result</returns>
93-
public static bool IsAdmin(this Customer customer, bool onlyActiveCustomerRoles = true)
87+
/// <summary>
88+
/// Gets a value indicating whether customer is administrator
89+
/// </summary>
90+
/// <param name="customer">Customer</param>
91+
/// <param name="onlyActiveCustomerRoles">A value indicating whether we should look only in active customer roles</param>
92+
/// <returns>Result</returns>
93+
public static bool IsAdmin(this Customer customer, bool onlyActiveCustomerRoles = true)
9494
{
9595
return IsInCustomerRole(customer, SystemCustomerRoleNames.Administrators, onlyActiveCustomerRoles);
9696
}

0 commit comments

Comments
 (0)