mirror of
https://git.teknik.io/Teknikode/Teknik.git
synced 2023-08-02 14:16:22 +02:00
Added IP and Referrer blacklists.
This commit is contained in:
parent
8827992935
commit
bea394cbaf
0
Teknik/App_Data/ipBlacklist.txt
Normal file
0
Teknik/App_Data/ipBlacklist.txt
Normal file
1
Teknik/App_Data/referrerBlacklist.txt
Normal file
1
Teknik/App_Data/referrerBlacklist.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
xn--cckl0itdpc9763ahlyc.tv
|
178
Teknik/Modules/BlacklistModule.cs
Normal file
178
Teknik/Modules/BlacklistModule.cs
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.ServiceModel.Channels;
|
||||||
|
using System.Web;
|
||||||
|
using System.Web.Caching;
|
||||||
|
using System.Web.Helpers;
|
||||||
|
using System.Web.Mvc;
|
||||||
|
using System.Web.Routing;
|
||||||
|
using Teknik.Areas.Error.Controllers;
|
||||||
|
using Teknik.Configuration;
|
||||||
|
|
||||||
|
namespace Teknik.Modules
|
||||||
|
{
|
||||||
|
public class BlacklistModule : IHttpModule
|
||||||
|
{
|
||||||
|
|
||||||
|
private EventHandler onBeginRequest;
|
||||||
|
|
||||||
|
public BlacklistModule()
|
||||||
|
{
|
||||||
|
onBeginRequest = new EventHandler(this.HandleBeginRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHttpModule.Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHttpModule.Init(HttpApplication context)
|
||||||
|
{
|
||||||
|
context.BeginRequest += onBeginRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Referrer Info
|
||||||
|
private const string BLOCKEDREFERRERKEY = "BlockedReferrer";
|
||||||
|
private static string referrerFileName = null;
|
||||||
|
private static object referrerFileNameObj = new object();
|
||||||
|
|
||||||
|
public static string GetReferrerFilePath()
|
||||||
|
{
|
||||||
|
if (referrerFileName != null)
|
||||||
|
return referrerFileName;
|
||||||
|
lock (referrerFileNameObj)
|
||||||
|
{
|
||||||
|
if (referrerFileName == null)
|
||||||
|
{
|
||||||
|
Config config = Config.Load();
|
||||||
|
referrerFileName = config.ReferrerBlacklistFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return referrerFileName;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IP Info
|
||||||
|
private const string BLOCKEDIPKEY = "BlockedIP";
|
||||||
|
private static string ipFileName = null;
|
||||||
|
private static object ipFileNameObj = new object();
|
||||||
|
|
||||||
|
public static string GetIPFilePath()
|
||||||
|
{
|
||||||
|
if (ipFileName != null)
|
||||||
|
return ipFileName;
|
||||||
|
lock (ipFileNameObj)
|
||||||
|
{
|
||||||
|
if (ipFileName == null)
|
||||||
|
{
|
||||||
|
Config config = Config.Load();
|
||||||
|
ipFileName = config.IPBlacklistFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ipFileName;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public static StringDictionary GetFileData(HttpContext context, string key, Func<string> fn)
|
||||||
|
{
|
||||||
|
StringDictionary data = (StringDictionary)context.Cache[key];
|
||||||
|
if (data == null)
|
||||||
|
{
|
||||||
|
string filePath = fn();
|
||||||
|
data = GetFileLines(filePath);
|
||||||
|
context.Cache.Insert(key, data, new CacheDependency(filePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StringDictionary GetFileLines(string configPath)
|
||||||
|
{
|
||||||
|
StringDictionary retval = new StringDictionary();
|
||||||
|
if (File.Exists(configPath))
|
||||||
|
{
|
||||||
|
using (StreamReader sr = new StreamReader(configPath))
|
||||||
|
{
|
||||||
|
String line;
|
||||||
|
while ((line = sr.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
line = line.Trim();
|
||||||
|
if (line.Length != 0)
|
||||||
|
{
|
||||||
|
retval.Add(line, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleBeginRequest(object sender, EventArgs evargs)
|
||||||
|
{
|
||||||
|
HttpApplication app = sender as HttpApplication;
|
||||||
|
|
||||||
|
if (app != null)
|
||||||
|
{
|
||||||
|
bool blocked = false;
|
||||||
|
string blockReason = string.Empty;
|
||||||
|
|
||||||
|
#region Detect Blacklisted IPs
|
||||||
|
if (!blocked)
|
||||||
|
{
|
||||||
|
string IPAddr = app.Context.Request.ServerVariables["REMOTE_ADDR"];
|
||||||
|
if (!string.IsNullOrEmpty(IPAddr))
|
||||||
|
{
|
||||||
|
StringDictionary badIPs = GetFileData(app.Context, BLOCKEDIPKEY, GetIPFilePath);
|
||||||
|
|
||||||
|
blocked |= (badIPs != null && badIPs.ContainsKey(IPAddr));
|
||||||
|
blockReason = $"This IP address ({IPAddr}) has been blacklisted. If you feel this is in error, please contact support@teknik.io for assistance.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Detect Blacklisted Referrers
|
||||||
|
if (!blocked)
|
||||||
|
{
|
||||||
|
string referrer = app.Context.Request.UrlReferrer?.Host;
|
||||||
|
if (!string.IsNullOrEmpty(referrer))
|
||||||
|
{
|
||||||
|
StringDictionary badReferrers = GetFileData(app.Context, BLOCKEDREFERRERKEY, GetReferrerFilePath);
|
||||||
|
|
||||||
|
blocked |= (badReferrers != null && badReferrers.ContainsKey(referrer));
|
||||||
|
blockReason = $"This referrer ({referrer}) has been blacklisted. If you feel this is in error, please contact support@teknik.io for assistance.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
if (blocked)
|
||||||
|
{
|
||||||
|
// Clear the response
|
||||||
|
app.Context.Response.Clear();
|
||||||
|
|
||||||
|
RouteData routeData = new RouteData();
|
||||||
|
routeData.DataTokens.Add("namespaces", new[] { typeof(ErrorController).Namespace });
|
||||||
|
routeData.DataTokens.Add("area", "Error");
|
||||||
|
routeData.Values.Add("controller", "Error");
|
||||||
|
routeData.Values.Add("scheme", "https");
|
||||||
|
routeData.Values.Add("action", "Http403");
|
||||||
|
|
||||||
|
// Clear the error on server.
|
||||||
|
app.Context.Server.ClearError();
|
||||||
|
|
||||||
|
// Avoid IIS7 getting in the middle
|
||||||
|
app.Context.Response.TrySkipIisCustomErrors = true;
|
||||||
|
|
||||||
|
string jsonResult = Json.Encode(new { error = new { type = "Blacklist", message = blockReason } });
|
||||||
|
app.Context.Response.Write(jsonResult);
|
||||||
|
app.Context.Response.End();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -29,46 +29,45 @@ namespace Teknik.Modules
|
|||||||
string username = string.Empty;
|
string username = string.Empty;
|
||||||
|
|
||||||
bool hasAuthToken = false;
|
bool hasAuthToken = false;
|
||||||
if (context.Request != null)
|
if (context.Request.Headers.HasKeys())
|
||||||
{
|
{
|
||||||
if (context.Request.Headers.HasKeys())
|
string auth = context.Request.Headers["Authorization"];
|
||||||
|
if (!string.IsNullOrEmpty(auth))
|
||||||
{
|
{
|
||||||
string auth = context.Request.Headers["Authorization"];
|
string[] parts = auth.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (!string.IsNullOrEmpty(auth))
|
string type = string.Empty;
|
||||||
|
string value = string.Empty;
|
||||||
|
if (parts.Length > 0)
|
||||||
{
|
{
|
||||||
string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
type = parts[0].ToLower();
|
||||||
string type = string.Empty;
|
}
|
||||||
string value = string.Empty;
|
|
||||||
if (parts.Length > 0)
|
|
||||||
{
|
|
||||||
type = parts[0].ToLower();
|
|
||||||
}
|
|
||||||
if (parts.Length > 1)
|
|
||||||
{
|
|
||||||
value = parts[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
using (TeknikEntities entities = new TeknikEntities())
|
if (parts.Length > 1)
|
||||||
|
{
|
||||||
|
value = parts[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
using (TeknikEntities entities = new TeknikEntities())
|
||||||
|
{
|
||||||
|
// Get the user information based on the auth type
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
// Get the user information based on the auth type
|
case "basic":
|
||||||
switch (type)
|
KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value);
|
||||||
{
|
|
||||||
case "basic":
|
|
||||||
KeyValuePair<string, string> authCreds = StringHelper.ParseBasicAuthHeader(value);
|
|
||||||
|
|
||||||
bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
|
bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
|
||||||
if (tokenValid)
|
if (tokenValid)
|
||||||
{
|
{
|
||||||
// it's valid, so let's update it's Last Used date
|
// it's valid, so let's update it's Last Used date
|
||||||
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);
|
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);
|
||||||
|
|
||||||
// Set the username
|
// Set the username
|
||||||
username = authCreds.Key;
|
username = authCreds.Key;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
break;
|
||||||
break;
|
default:
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -321,6 +321,7 @@
|
|||||||
<Compile Include="Areas\Vault\ViewModels\VaultItemViewModel.cs" />
|
<Compile Include="Areas\Vault\ViewModels\VaultItemViewModel.cs" />
|
||||||
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" />
|
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" />
|
||||||
<Compile Include="Hubs\IRCClientHub.cs" />
|
<Compile Include="Hubs\IRCClientHub.cs" />
|
||||||
|
<Compile Include="Modules\BlacklistModule.cs" />
|
||||||
<Compile Include="Modules\UserAuthModule.cs" />
|
<Compile Include="Modules\UserAuthModule.cs" />
|
||||||
<Compile Include="Security\ITeknikPrincipal.cs" />
|
<Compile Include="Security\ITeknikPrincipal.cs" />
|
||||||
<Compile Include="Security\TeknikPrincipal.cs" />
|
<Compile Include="Security\TeknikPrincipal.cs" />
|
||||||
@ -395,6 +396,8 @@
|
|||||||
<Compile Include="BaseViewPage.cs" />
|
<Compile Include="BaseViewPage.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Content Include="App_Data\ipBlacklist.txt" />
|
||||||
|
<Content Include="App_Data\referrerBlacklist.txt" />
|
||||||
<Content Include="App_Data\reservedUsernames.txt">
|
<Content Include="App_Data\reservedUsernames.txt">
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -56,6 +56,7 @@
|
|||||||
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
|
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
|
||||||
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" />
|
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" />
|
||||||
<add name="UserAuthModule" type="Teknik.Modules.UserAuthModule, Teknik" />
|
<add name="UserAuthModule" type="Teknik.Modules.UserAuthModule, Teknik" />
|
||||||
|
<add name="BlacklistModule" type="Teknik.Modules.BlacklistModule, Teknik" />
|
||||||
<remove name="UrlRoutingModule-4.0" />
|
<remove name="UrlRoutingModule-4.0" />
|
||||||
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
|
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
|
||||||
</modules>
|
</modules>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@ -29,6 +29,8 @@ namespace Teknik.Configuration
|
|||||||
private string _Salt1;
|
private string _Salt1;
|
||||||
private string _Salt2;
|
private string _Salt2;
|
||||||
private string _CdnHost;
|
private string _CdnHost;
|
||||||
|
private string _IPBlacklistFile;
|
||||||
|
private string _ReferrerBlacklistFile;
|
||||||
private UserConfig _UserConfig;
|
private UserConfig _UserConfig;
|
||||||
private ContactConfig _ContactConfig;
|
private ContactConfig _ContactConfig;
|
||||||
private EmailConfig _EmailConfig;
|
private EmailConfig _EmailConfig;
|
||||||
@ -46,21 +48,23 @@ namespace Teknik.Configuration
|
|||||||
private PiwikConfig _PiwikConfig;
|
private PiwikConfig _PiwikConfig;
|
||||||
private IRCConfig _IRCConfig;
|
private IRCConfig _IRCConfig;
|
||||||
|
|
||||||
public bool DevEnvironment { get { return _DevEnvironment; } set { _DevEnvironment = value; } }
|
public bool DevEnvironment { get { return _DevEnvironment; } set { _DevEnvironment = value; } }
|
||||||
public bool Migrate { get { return _Migrate; } set { _Migrate = value; } }
|
public bool Migrate { get { return _Migrate; } set { _Migrate = value; } }
|
||||||
public bool UseCdn { get { return _UseCdn; } set { _UseCdn = value; } }
|
public bool UseCdn { get { return _UseCdn; } set { _UseCdn = value; } }
|
||||||
|
|
||||||
// Site Information
|
// Site Information
|
||||||
public string Title { get { return _Title; } set { _Title = value; } }
|
public string Title { get { return _Title; } set { _Title = value; } }
|
||||||
public string Description { get { return _Description; } set { _Description = value; } }
|
public string Description { get { return _Description; } set { _Description = value; } }
|
||||||
public string Author { get { return _Author; } set { _Author = value; } }
|
public string Author { get { return _Author; } set { _Author = value; } }
|
||||||
public string Host { get { return _Host; } set { _Host = value; } }
|
public string Host { get { return _Host; } set { _Host = value; } }
|
||||||
public string SupportEmail { get { return _SupportEmail; } set { _SupportEmail = value; } }
|
public string SupportEmail { get { return _SupportEmail; } set { _SupportEmail = value; } }
|
||||||
public string NoReplyEmail { get { return _NoReplyEmail; } set { _NoReplyEmail = value; } }
|
public string NoReplyEmail { get { return _NoReplyEmail; } set { _NoReplyEmail = value; } }
|
||||||
public string BitcoinAddress { get { return _BitcoinAddress; } set { _BitcoinAddress = value; } }
|
public string BitcoinAddress { get { return _BitcoinAddress; } set { _BitcoinAddress = value; } }
|
||||||
public string Salt1 { get { return _Salt1; } set { _Salt1 = value; } }
|
public string Salt1 { get { return _Salt1; } set { _Salt1 = value; } }
|
||||||
public string Salt2 { get { return _Salt2; } set { _Salt2 = value; } }
|
public string Salt2 { get { return _Salt2; } set { _Salt2 = value; } }
|
||||||
public string CdnHost { get { return _CdnHost; } set { _CdnHost = value; } }
|
public string CdnHost { get { return _CdnHost; } set { _CdnHost = value; } }
|
||||||
|
public string IPBlacklistFile { get { return _IPBlacklistFile;} set { _IPBlacklistFile = value; }}
|
||||||
|
public string ReferrerBlacklistFile { get { return _ReferrerBlacklistFile;} set { _ReferrerBlacklistFile = value; }}
|
||||||
|
|
||||||
// User Configuration
|
// User Configuration
|
||||||
public UserConfig UserConfig { get { return _UserConfig; } set { _UserConfig = value; } }
|
public UserConfig UserConfig { get { return _UserConfig; } set { _UserConfig = value; } }
|
||||||
@ -122,35 +126,37 @@ namespace Teknik.Configuration
|
|||||||
|
|
||||||
public void SetDefaults()
|
public void SetDefaults()
|
||||||
{
|
{
|
||||||
DevEnvironment = false;
|
DevEnvironment = false;
|
||||||
Migrate = false;
|
Migrate = false;
|
||||||
UseCdn = false;
|
UseCdn = false;
|
||||||
Title = string.Empty;
|
Title = string.Empty;
|
||||||
Description = string.Empty;
|
Description = string.Empty;
|
||||||
Author = string.Empty;
|
Author = string.Empty;
|
||||||
Host = string.Empty;
|
Host = string.Empty;
|
||||||
SupportEmail = string.Empty;
|
SupportEmail = string.Empty;
|
||||||
NoReplyEmail = string.Empty;
|
NoReplyEmail = string.Empty;
|
||||||
BitcoinAddress = string.Empty;
|
BitcoinAddress = string.Empty;
|
||||||
Salt1 = string.Empty;
|
Salt1 = string.Empty;
|
||||||
Salt2 = string.Empty;
|
Salt2 = string.Empty;
|
||||||
CdnHost = string.Empty;
|
CdnHost = string.Empty;
|
||||||
UserConfig = new UserConfig();
|
IPBlacklistFile = string.Empty;
|
||||||
EmailConfig = new EmailConfig();
|
ReferrerBlacklistFile = string.Empty;
|
||||||
ContactConfig = new ContactConfig();
|
UserConfig = new UserConfig();
|
||||||
GitConfig = new GitConfig();
|
EmailConfig = new EmailConfig();
|
||||||
BlogConfig = new BlogConfig();
|
ContactConfig = new ContactConfig();
|
||||||
UploadConfig = new UploadConfig();
|
GitConfig = new GitConfig();
|
||||||
PasteConfig = new PasteConfig();
|
BlogConfig = new BlogConfig();
|
||||||
ApiConfig = new ApiConfig();
|
UploadConfig = new UploadConfig();
|
||||||
PodcastConfig = new PodcastConfig();
|
PasteConfig = new PasteConfig();
|
||||||
StreamConfig = new StreamConfig();
|
ApiConfig = new ApiConfig();
|
||||||
ShortenerConfig = new ShortenerConfig();
|
PodcastConfig = new PodcastConfig();
|
||||||
VaultConfig = new VaultConfig();
|
StreamConfig = new StreamConfig();
|
||||||
StatusConfig = new StatusConfig();
|
ShortenerConfig = new ShortenerConfig();
|
||||||
LoggingConfig = new LoggingConfig();
|
VaultConfig = new VaultConfig();
|
||||||
PiwikConfig = new PiwikConfig();
|
StatusConfig = new StatusConfig();
|
||||||
IRCConfig = new IRCConfig();
|
LoggingConfig = new LoggingConfig();
|
||||||
|
PiwikConfig = new PiwikConfig();
|
||||||
|
IRCConfig = new IRCConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Config Deserialize(string text)
|
public static Config Deserialize(string text)
|
||||||
@ -210,4 +216,4 @@ namespace Teknik.Configuration
|
|||||||
File.WriteAllText(path, configContents);
|
File.WriteAllText(path, configContents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user