Skip to content

Commit

Permalink
feat(experimental): use nonce for csp
Browse files Browse the repository at this point in the history
  • Loading branch information
GZTimeWalker committed May 22, 2024
1 parent a244152 commit c422552
Show file tree
Hide file tree
Showing 25 changed files with 57 additions and 58 deletions.
2 changes: 1 addition & 1 deletion src/GZCTF.Test/ConfigServiceTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Collections.Generic;
using GZCTF.Models.Data;
using GZCTF.Models.Internal;
using GZCTF.Services;
using GZCTF.Services.Config;
using Xunit;
using Xunit.Abstractions;

Expand Down
6 changes: 6 additions & 0 deletions src/GZCTF/ClientApp/src/components/Captcha.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ const Captcha = forwardRef<CaptchaInstance, CaptchaProps>((props, ref) => {
const type = info?.type ?? CaptchaProvider.None
const turnstileRef = useRef<TurnstileInstance>(null)
const reCaptchaRef = useRef<CaptchaInstance>(null)
const nonce =
document.querySelector('meta[property="csp-nonce"]')?.getAttribute('nonce') ?? undefined

useImperativeHandle(
ref,
Expand Down Expand Up @@ -99,6 +101,9 @@ const Captcha = forwardRef<CaptchaInstance, CaptchaProps>((props, ref) => {
return (
<GoogleReCaptchaProvider
reCaptchaKey={info.siteKey}
scriptProps={{
nonce,
}}
container={{
parameters: {
theme: colorScheme == 'auto' ? undefined : colorScheme,
Expand All @@ -114,6 +119,7 @@ const Captcha = forwardRef<CaptchaInstance, CaptchaProps>((props, ref) => {
<Box {...others}>
<Turnstile
ref={turnstileRef}
nonce={nonce}
siteKey={info.siteKey}
options={{
theme: colorScheme,
Expand Down
3 changes: 3 additions & 0 deletions src/GZCTF/ClientApp/vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default defineConfig(({ mode }) => {
},
},
},
html: {
cspNonce: '%nonce%',
},
plugins: [
react(),
tsconfigPaths(),
Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Controllers/AccountController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using GZCTF.Models.Internal;
using GZCTF.Models.Request.Account;
using GZCTF.Repositories.Interface;
using GZCTF.Services.Interface;
using GZCTF.Services.Mail;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.RateLimiting;
Expand Down
3 changes: 1 addition & 2 deletions src/GZCTF/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,11 @@
using GZCTF.Models.Request.Info;
using GZCTF.Repositories.Interface;
using GZCTF.Services.Cache;
using GZCTF.Services.Interface;
using GZCTF.Services.Config;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;

Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Controllers/EditController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
using GZCTF.Models.Request.Info;
using GZCTF.Repositories.Interface;
using GZCTF.Services.Cache;
using GZCTF.Services.Interface;
using GZCTF.Services.Container.Manager;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
Expand Down
20 changes: 17 additions & 3 deletions src/GZCTF/Extensions/ConfigurationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.Mime;
using System.Security.Cryptography;
using System.Text.Encodings.Web;
using GZCTF.Models.Internal;
using GZCTF.Providers;
Expand All @@ -17,6 +18,9 @@ public static class ConfigurationExtensions
AbsoluteExpirationRelativeToNow = TimeSpan.FromDays(7)
};

const string CspTemplate = "default-src 'self' 'nonce-{0}'; style-src 'self' 'unsafe-inline'; " +
"img-src * 'self' data:; font-src * 'self' data:; object-src 'none'; frame-src 'none';";

public static void AddEntityConfiguration(this IConfigurationBuilder builder,
Action<DbContextOptionsBuilder> optionsAction) =>
builder.Add(new EntityConfigurationSource(optionsAction));
Expand Down Expand Up @@ -96,25 +100,35 @@ static async Task<IResult> FaviconHandler(
}

static HomePageHandlerDelegate IndexHandler(string template) => async (
HttpContext context,
IDistributedCache cache,
IOptionsSnapshot<GlobalConfig> globalConfig,
CancellationToken token = default) =>
{
var content = await cache.GetStringAsync(CacheKey.Index, token);
if (content is not null)
return Results.Text(content, MediaTypeNames.Text.Html);
goto SendContent;
GlobalConfig config = globalConfig.Value;
var title = HtmlEncoder.Default.Encode(config.Platform);
var descr = HtmlEncoder.Default.Encode(config.Description ?? GlobalConfig.DefaultDescription);
content = template.Replace("%title%", title).Replace("%description%", descr);
content = template.Replace("%title%", title)
.Replace("%description%", descr);
await cache.SetStringAsync(CacheKey.Index, content, token);
return Results.Text(content, MediaTypeNames.Text.Html);
SendContent:
var nonce = Convert.ToBase64String(RandomNumberGenerator.GetBytes(16));
context.Response.Headers.ContentSecurityPolicy = string.Format(CspTemplate, nonce);
return Results.Text(content.Replace("%nonce%", nonce), MediaTypeNames.Text.Html);
};

delegate Task<IResult> HomePageHandlerDelegate(
HttpContext context,
IDistributedCache cache,
IOptionsSnapshot<GlobalConfig> globalConfig,
CancellationToken token = default);
Expand Down
19 changes: 0 additions & 19 deletions src/GZCTF/Middlewares/CspMiddleware.cs

This file was deleted.

5 changes: 2 additions & 3 deletions src/GZCTF/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
using GZCTF.Repositories.Interface;
using GZCTF.Services;
using GZCTF.Services.Cache;
using GZCTF.Services.Config;
using GZCTF.Services.Container;
using GZCTF.Services.Interface;
using GZCTF.Services.Mail;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity;
Expand Down Expand Up @@ -296,8 +297,6 @@

app.UseResponseCompression();

app.UseCspMiddleware();

app.UseCustomFavicon();
app.UseStaticFiles(new StaticFileOptions
{
Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Providers/EntityConfigurationProvider.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Security.Cryptography;
using System.Text;
using GZCTF.Models.Internal;
using GZCTF.Services;
using GZCTF.Services.Config;
using Microsoft.EntityFrameworkCore;
using Serilog;

Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Repositories/ContainerRepository.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using GZCTF.Models.Request.Admin;
using GZCTF.Repositories.Interface;
using GZCTF.Services.Cache;
using GZCTF.Services.Interface;
using GZCTF.Services.Container.Manager;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;

Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Repositories/ExerciseInstanceRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using GZCTF.Models.Internal;
using GZCTF.Repositories.Interface;
using GZCTF.Services.Cache;
using GZCTF.Services.Interface;
using GZCTF.Services.Container.Manager;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Caching.Distributed;
Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Repositories/GameInstanceRepository.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using GZCTF.Models.Internal;
using GZCTF.Repositories.Interface;
using GZCTF.Services.Interface;
using GZCTF.Services.Container.Manager;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.Localization;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
using System.ComponentModel;
using System.Reflection;
using GZCTF.Models.Internal;
using GZCTF.Services.Interface;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using ConfigModel = GZCTF.Models.Data.Config;

namespace GZCTF.Services;
namespace GZCTF.Services.Config;

public class ConfigService(
AppDbContext context,
Expand All @@ -23,15 +23,15 @@ public Task SaveConfig<T>(T config, CancellationToken token = default) where T :

public void ReloadConfig() => _configuration?.Reload();

public async Task SaveConfigSet(HashSet<Config> configs, CancellationToken token = default)
public async Task SaveConfigSet(HashSet<ConfigModel> configs, CancellationToken token = default)
{
Dictionary<string, Config> dbConfigs = await context.Configs
Dictionary<string, ConfigModel> dbConfigs = await context.Configs
.ToDictionaryAsync(c => c.ConfigKey, c => c, token);
HashSet<string> cacheKeys = [];

foreach (Config conf in configs)
foreach (ConfigModel conf in configs)
{
if (dbConfigs.TryGetValue(conf.ConfigKey, out Config? dbConf))
if (dbConfigs.TryGetValue(conf.ConfigKey, out ConfigModel? dbConf))
{
if (dbConf.Value == conf.Value)
continue;
Expand Down Expand Up @@ -68,7 +68,7 @@ public async Task SaveConfigSet(HashSet<Config> configs, CancellationToken token
await cache.RemoveAsync(key, token);
}

static void MapConfigsInternal(string key, HashSet<Config> configs, PropertyInfo info, object? value)
static void MapConfigsInternal(string key, HashSet<ConfigModel> configs, PropertyInfo info, object? value)
{
// ignore when value with `AutoSaveIgnoreAttribute`
if (value is null || info.GetCustomAttribute<AutoSaveIgnoreAttribute>() != null)
Expand All @@ -94,19 +94,19 @@ static void MapConfigsInternal(string key, HashSet<Config> configs, PropertyInfo
}
}

static HashSet<Config> GetConfigs(Type type, object? value)
static HashSet<ConfigModel> GetConfigs(Type type, object? value)
{
HashSet<Config> configs = [];
HashSet<ConfigModel> configs = [];

foreach (PropertyInfo item in type.GetProperties())
MapConfigsInternal($"{type.Name}:{item.Name}", configs, item, item.GetValue(value));

return configs;
}

public static HashSet<Config> GetConfigs<T>(T config) where T : class
public static HashSet<ConfigModel> GetConfigs<T>(T config) where T : class
{
HashSet<Config> configs = [];
HashSet<ConfigModel> configs = [];
Type type = typeof(T);

foreach (PropertyInfo item in type.GetProperties())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace GZCTF.Services.Interface;
using ConfigModel = GZCTF.Models.Data.Config;

namespace GZCTF.Services.Config;

public interface IConfigService
{
Expand All @@ -25,7 +27,7 @@ public interface IConfigService
/// </summary>
/// <param name="configs">键值对</param>
/// <param name="token"></param>
public Task SaveConfigSet(HashSet<Config> configs, CancellationToken token = default);
public Task SaveConfigSet(HashSet<ConfigModel> configs, CancellationToken token = default);

/// <summary>
/// 重载配置
Expand Down
1 change: 0 additions & 1 deletion src/GZCTF/Services/Container/ContainerServiceExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using GZCTF.Models.Internal;
using GZCTF.Services.Container.Manager;
using GZCTF.Services.Container.Provider;
using GZCTF.Services.Interface;
using k8s;

namespace GZCTF.Services.Container;
Expand Down
1 change: 0 additions & 1 deletion src/GZCTF/Services/Container/Manager/DockerManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Docker.DotNet.Models;
using GZCTF.Models.Internal;
using GZCTF.Services.Container.Provider;
using GZCTF.Services.Interface;
using ContainerStatus = GZCTF.Utils.ContainerStatus;

namespace GZCTF.Services.Container.Manager;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using GZCTF.Models.Internal;

namespace GZCTF.Services.Interface;
namespace GZCTF.Services.Container.Manager;

public interface IContainerManager
{
Expand Down
1 change: 0 additions & 1 deletion src/GZCTF/Services/Container/Manager/KubernetesManager.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Net;
using GZCTF.Models.Internal;
using GZCTF.Services.Container.Provider;
using GZCTF.Services.Interface;
using k8s;
using k8s.Autorest;
using k8s.Models;
Expand Down
1 change: 0 additions & 1 deletion src/GZCTF/Services/Container/Manager/SwarmManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Docker.DotNet.Models;
using GZCTF.Models.Internal;
using GZCTF.Services.Container.Provider;
using GZCTF.Services.Interface;
using ContainerStatus = GZCTF.Utils.ContainerStatus;

namespace GZCTF.Services.Container.Manager;
Expand Down
2 changes: 1 addition & 1 deletion src/GZCTF/Services/Container/Provider/DockerProvider.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Docker.DotNet;
using Docker.DotNet.Models;
using GZCTF.Models.Internal;
using GZCTF.Services.Interface;
using GZCTF.Services.Container.Provider;
using Microsoft.Extensions.Options;

namespace GZCTF.Services.Container.Provider;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace GZCTF.Services.Interface;
namespace GZCTF.Services.Container.Provider;

public interface IContainerProvider<T, M>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json;
using GZCTF.Models.Internal;
using GZCTF.Services.Interface;
using GZCTF.Services.Container.Provider;
using k8s;
using k8s.Models;
using Microsoft.Extensions.Options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;

namespace GZCTF.Services.Interface;
namespace GZCTF.Services.Mail;

public interface IMailSender
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
using System.Net.Security;
using System.Text;
using GZCTF.Models.Internal;
using GZCTF.Services.Interface;
using MailKit.Net.Smtp;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using MimeKit;
using MimeKit.Text;

namespace GZCTF.Services;
namespace GZCTF.Services.Mail;

public sealed class MailSender : IMailSender, IDisposable
{
Expand Down

0 comments on commit c422552

Please sign in to comment.