Browse Source

Added IP and Referrer blacklists.

tags/3.0.0
Teknikode 1 year ago
parent
commit
bea394cbaf

+ 0
- 0
Teknik/App_Data/ipBlacklist.txt View File


+ 1
- 0
Teknik/App_Data/referrerBlacklist.txt View File

@@ -0,0 +1 @@
xn--cckl0itdpc9763ahlyc.tv

+ 178
- 0
Teknik/Modules/BlacklistModule.cs View 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;
}
}
}
}
}

+ 32
- 33
Teknik/Modules/UserAuthModule.cs View File

@@ -29,46 +29,45 @@ namespace Teknik.Modules
string username = string.Empty;

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"];
if (!string.IsNullOrEmpty(auth))
string[] parts = auth.Split(new char[] {' '}, StringSplitOptions.RemoveEmptyEntries);
string type = string.Empty;
string value = string.Empty;
if (parts.Length > 0)
{
string[] parts = auth.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
string type = string.Empty;
string value = string.Empty;
if (parts.Length > 0)
{
type = parts[0].ToLower();
}
if (parts.Length > 1)
{
value = parts[1];
}
type = parts[0].ToLower();
}

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
switch (type)
{
case "basic":
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);
if (tokenValid)
{
// it's valid, so let's update it's Last Used date
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);

bool tokenValid = UserHelper.UserTokenCorrect(entities, authCreds.Key, authCreds.Value);
if (tokenValid)
{
// it's valid, so let's update it's Last Used date
UserHelper.UpdateTokenLastUsed(entities, authCreds.Key, authCreds.Value, DateTime.Now);
// Set the username
username = authCreds.Key;
}

// Set the username
username = authCreds.Key;
}
break;
default:
break;
}
break;
default:
break;
}
}
}

+ 3
- 0
Teknik/Teknik.csproj View File

@@ -321,6 +321,7 @@
<Compile Include="Areas\Vault\ViewModels\VaultItemViewModel.cs" />
<Compile Include="Attributes\TeknikAuthorizeAttribute.cs" />
<Compile Include="Hubs\IRCClientHub.cs" />
<Compile Include="Modules\BlacklistModule.cs" />
<Compile Include="Modules\UserAuthModule.cs" />
<Compile Include="Security\ITeknikPrincipal.cs" />
<Compile Include="Security\TeknikPrincipal.cs" />
@@ -395,6 +396,8 @@
<Compile Include="BaseViewPage.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="App_Data\ipBlacklist.txt" />
<Content Include="App_Data\referrerBlacklist.txt" />
<Content Include="App_Data\reservedUsernames.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>

+ 1
- 0
Teknik/Web.config View File

@@ -56,6 +56,7 @@
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<add name="PerfModule" type="Teknik.Modules.PerformanceMonitorModule, Teknik" />
<add name="UserAuthModule" type="Teknik.Modules.UserAuthModule, Teknik" />
<add name="BlacklistModule" type="Teknik.Modules.BlacklistModule, Teknik" />
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>

+ 50
- 44
Utilities/Configuration/Config.cs View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Threading;
using Newtonsoft.Json;
@@ -29,6 +29,8 @@ namespace Teknik.Configuration
private string _Salt1;
private string _Salt2;
private string _CdnHost;
private string _IPBlacklistFile;
private string _ReferrerBlacklistFile;
private UserConfig _UserConfig;
private ContactConfig _ContactConfig;
private EmailConfig _EmailConfig;
@@ -46,21 +48,23 @@ namespace Teknik.Configuration
private PiwikConfig _PiwikConfig;
private IRCConfig _IRCConfig;

public bool DevEnvironment { get { return _DevEnvironment; } set { _DevEnvironment = value; } }
public bool Migrate { get { return _Migrate; } set { _Migrate = value; } }
public bool UseCdn { get { return _UseCdn; } set { _UseCdn = value; } }
public bool DevEnvironment { get { return _DevEnvironment; } set { _DevEnvironment = value; } }
public bool Migrate { get { return _Migrate; } set { _Migrate = value; } }
public bool UseCdn { get { return _UseCdn; } set { _UseCdn = value; } }

// Site Information
public string Title { get { return _Title; } set { _Title = value; } }
public string Description { get { return _Description; } set { _Description = value; } }
public string Author { get { return _Author; } set { _Author = value; } }
public string Host { get { return _Host; } set { _Host = value; } }
public string SupportEmail { get { return _SupportEmail; } set { _SupportEmail = value; } }
public string NoReplyEmail { get { return _NoReplyEmail; } set { _NoReplyEmail = value; } }
public string BitcoinAddress { get { return _BitcoinAddress; } set { _BitcoinAddress = value; } }
public string Salt1 { get { return _Salt1; } set { _Salt1 = value; } }
public string Salt2 { get { return _Salt2; } set { _Salt2 = value; } }
public string CdnHost { get { return _CdnHost; } set { _CdnHost = value; } }
public string Title { get { return _Title; } set { _Title = value; } }
public string Description { get { return _Description; } set { _Description = value; } }
public string Author { get { return _Author; } set { _Author = value; } }
public string Host { get { return _Host; } set { _Host = value; } }
public string SupportEmail { get { return _SupportEmail; } set { _SupportEmail = value; } }
public string NoReplyEmail { get { return _NoReplyEmail; } set { _NoReplyEmail = value; } }
public string BitcoinAddress { get { return _BitcoinAddress; } set { _BitcoinAddress = value; } }
public string Salt1 { get { return _Salt1; } set { _Salt1 = value; } }
public string Salt2 { get { return _Salt2; } set { _Salt2 = 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
public UserConfig UserConfig { get { return _UserConfig; } set { _UserConfig = value; } }
@@ -122,35 +126,37 @@ namespace Teknik.Configuration

public void SetDefaults()
{
DevEnvironment = false;
Migrate = false;
UseCdn = false;
Title = string.Empty;
Description = string.Empty;
Author = string.Empty;
Host = string.Empty;
SupportEmail = string.Empty;
NoReplyEmail = string.Empty;
BitcoinAddress = string.Empty;
Salt1 = string.Empty;
Salt2 = string.Empty;
CdnHost = string.Empty;
UserConfig = new UserConfig();
EmailConfig = new EmailConfig();
ContactConfig = new ContactConfig();
GitConfig = new GitConfig();
BlogConfig = new BlogConfig();
UploadConfig = new UploadConfig();
PasteConfig = new PasteConfig();
ApiConfig = new ApiConfig();
PodcastConfig = new PodcastConfig();
StreamConfig = new StreamConfig();
ShortenerConfig = new ShortenerConfig();
VaultConfig = new VaultConfig();
StatusConfig = new StatusConfig();
LoggingConfig = new LoggingConfig();
PiwikConfig = new PiwikConfig();
IRCConfig = new IRCConfig();
DevEnvironment = false;
Migrate = false;
UseCdn = false;
Title = string.Empty;
Description = string.Empty;
Author = string.Empty;
Host = string.Empty;
SupportEmail = string.Empty;
NoReplyEmail = string.Empty;
BitcoinAddress = string.Empty;
Salt1 = string.Empty;
Salt2 = string.Empty;
CdnHost = string.Empty;
IPBlacklistFile = string.Empty;
ReferrerBlacklistFile = string.Empty;
UserConfig = new UserConfig();
EmailConfig = new EmailConfig();
ContactConfig = new ContactConfig();
GitConfig = new GitConfig();
BlogConfig = new BlogConfig();
UploadConfig = new UploadConfig();
PasteConfig = new PasteConfig();
ApiConfig = new ApiConfig();
PodcastConfig = new PodcastConfig();
StreamConfig = new StreamConfig();
ShortenerConfig = new ShortenerConfig();
VaultConfig = new VaultConfig();
StatusConfig = new StatusConfig();
LoggingConfig = new LoggingConfig();
PiwikConfig = new PiwikConfig();
IRCConfig = new IRCConfig();
}

public static Config Deserialize(string text)
@@ -210,4 +216,4 @@ namespace Teknik.Configuration
File.WriteAllText(path, configContents);
}
}
}
}

Loading…
Cancel
Save