Browse Source

Added security headers, and file download last modified/content type.

tags/3.0.0^2
Teknikode 1 year ago
parent
commit
9093c0f699

+ 5
- 0
Configuration/Config.cs View File

@@ -1,5 +1,6 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Teknik.Utilities.Cryptography;
@@ -33,6 +34,7 @@ namespace Teknik.Configuration
private string _CdnHost;
private string _IPBlacklistFile;
private string _ReferrerBlacklistFile;
private List<string> _PublicKeys;
private UserConfig _UserConfig;
private ContactConfig _ContactConfig;
private EmailConfig _EmailConfig;
@@ -68,6 +70,8 @@ namespace Teknik.Configuration
public string IPBlacklistFile { get { return _IPBlacklistFile;} set { _IPBlacklistFile = value; }}
public string ReferrerBlacklistFile { get { return _ReferrerBlacklistFile;} set { _ReferrerBlacklistFile = value; }}

public List<string> PublicKeys { get { return _PublicKeys; } set { _PublicKeys = value; } }

// User Configuration
public UserConfig UserConfig { get { return _UserConfig; } set { _UserConfig = value; } }

@@ -143,6 +147,7 @@ namespace Teknik.Configuration
CdnHost = string.Empty;
IPBlacklistFile = string.Empty;
ReferrerBlacklistFile = string.Empty;
PublicKeys = new List<string>();
UserConfig = new UserConfig();
EmailConfig = new EmailConfig();
ContactConfig = new ContactConfig();

+ 12
- 4
Teknik/Areas/Upload/Controllers/UploadController.cs View File

@@ -138,8 +138,7 @@ namespace Teknik.Areas.Upload.Controllers
return Json(new { error = new { message = "Exception while uploading file: " + ex.GetFullMessage(true) } });
}
}

// User did not supply key
[HttpGet]
[AllowAnonymous]
[ResponseCache(Duration = 31536000, Location = ResponseCacheLocation.Any)]
@@ -301,6 +300,9 @@ namespace Teknik.Areas.Upload.Controllers
}
#endregion

// Set Last Modified
Response.GetTypedHeaders().LastModified = dateUploaded;

// We accept ranges
Response.Headers.Add("Accept-Ranges", "0-" + contentLength);

@@ -310,6 +312,9 @@ namespace Teknik.Areas.Upload.Controllers
// Notify the client the content length we'll be outputting
Response.Headers.Add("Content-Length", length.ToString());

// Set the content type of this response
Response.Headers.Add("Content-Type", contentType);

// Create content disposition
var cd = new System.Net.Mime.ContentDisposition
{
@@ -333,12 +338,12 @@ namespace Teknik.Areas.Upload.Controllers
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
byte[] ivBytes = Encoding.UTF8.GetBytes(iv);

return new BufferedFileStreamResult(contentType, (response) => ResponseHelper.StreamToOutput(response, true, new AesCounterStream(fs, false, keyBytes, ivBytes), (int)length, _config.UploadConfig.ChunkSize), false);
return new BufferedFileStreamResult(contentType, async (response) => await ResponseHelper.StreamToOutput(response, true, new AesCounterStream(fs, false, keyBytes, ivBytes), (int)length, _config.UploadConfig.ChunkSize), false);
}
else // Otherwise just send it
{
// Send the file
return new BufferedFileStreamResult(contentType, (response) => ResponseHelper.StreamToOutput(response, true, fs, (int)length, _config.UploadConfig.ChunkSize), false);
return new BufferedFileStreamResult(contentType, async (response) => await ResponseHelper.StreamToOutput(response, true, fs, (int)length, _config.UploadConfig.ChunkSize), false);
}
}
catch (Exception ex)
@@ -376,6 +381,9 @@ namespace Teknik.Areas.Upload.Controllers
Inline = true
};

// Set the content type of this response
Response.Headers.Add("Content-Type", upload.ContentType);

Response.Headers.Add("Content-Disposition", cd.ToString());

// Read in the file

+ 1
- 0
Teknik/Middleware/CORSMiddleware.cs View File

@@ -55,6 +55,7 @@ namespace Teknik.Middleware
}

httpContext.Response.Headers.Append("Access-Control-Allow-Origin", origin);
httpContext.Response.Headers.Append("Vary", "Origin");

return _next(httpContext);
}

+ 61
- 0
Teknik/Middleware/SecurityHeadersMiddleware.cs View File

@@ -0,0 +1,61 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Teknik.Configuration;

namespace Teknik.Middleware
{
public class SecurityHeadersMiddleware
{
private readonly RequestDelegate _next;

public SecurityHeadersMiddleware(RequestDelegate next)
{
_next = next;
}

public Task Invoke(HttpContext httpContext, Config config)
{
IHeaderDictionary headers = httpContext.Response.Headers;

// Access Control
headers.Append("Access-Control-Allow-Credentials", "true");
headers.Append("Access-Control-Allow-Methods", "GET, PUT, POST, DELETE, OPTIONS");
headers.Append("Access-Control-Allow-Headers", "Authorization, Accept, Origin, Content-Type, X-Requested-With, Connection, Transfer-Encoding");

// HSTS
headers.Append("strict-transport-security", "max-age=31536000; includeSubdomains; preload");

// XSS Protection
headers.Append("X-XSS-Protection", "1; mode=block");

// Content Type Options
headers.Append("X-Content-Type-Options", "nosniff");

// Public Key Pinning
string keys = string.Empty;
foreach (string key in config.PublicKeys)
{
keys += $"pin-sha256=\"{key}\";";
}
headers.Append("Public-Key-Pins", $"max-age=300; includeSubDomains; {keys}");

// Referrer Policy
headers.Append("Referrer-Policy", "no-referrer, strict-origin-when-cross-origin");

return _next(httpContext);
}
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class SecurityHeadersMiddlewareExtensions
{
public static IApplicationBuilder UseSecurityHeaders(this IApplicationBuilder builder)
{
return builder.UseMiddleware<SecurityHeadersMiddleware>();
}
}
}

+ 2
- 1
Teknik/Startup.cs View File

@@ -144,7 +144,7 @@ namespace Teknik
}
else
{
app.UseHsts();
//app.UseHsts();
}

// Performance Monitor the entire request
@@ -154,6 +154,7 @@ namespace Teknik
app.UseBlacklist();
app.UseCORS();
app.UseCSP();
app.UseSecurityHeaders();

// Cache Responses
app.UseResponseCaching();

Loading…
Cancel
Save