博客 (53)

前面写过一篇文章介绍了不买高防 IP,照样抵挡 DDoS 攻击(IP 篇),如果攻击的是域名(CC),那么...


本文适用场景:攻击的是 web 网址而非 IP,来源有许多各地的 IP 地址,每个 IP 地址每小时只有若干请求,但整个网站每分钟有数万请求量。


《小白鼠A》(贵)

阿里云有一款产品叫“Web 应用防火墙”,开通并接入云产品,试用按量付费即可。

在防护配置-Web核心防护 中可配置各种规则,譬如:

“自定义规则”可添加网址/UA/IP/Cookie/等中包含某些关键词的请求;

“区域封禁”可按地区来限制请求;

另外还有“CC防护”等各种实用规则。

添加规则后记得关联实例。

配置完成后可在总览页面查看请求情况,如果攻击停止可关闭防火墙。

试用了12小时,平均每分钟请求2-5万次,消耗 15000SeCU,费用大概是750元。


《小白鼠B》(推荐)

阿里云有一款产品叫“边缘安全加速 ESA”,开通接入域名(注意填写域名时不要写 www)。

创建购买成功后会有一个 CNAME 域名,解析生效。配置 HTTPS 证书。

打开“我正在遭受攻击”,开启后站点进入严格防护模式,默认对所有 HTTP 请求做滑块挑战。这是非常能节省费用的操作,实测开启与不开启的数量相差20倍(具体视攻击强弱)。

另外,ESA 自带的“安全防护-WAF”中若想根据 URL 中包含某个关键词来拒绝请求,需要升级套餐。可以直接在“规则-重定向”设置 302 跳转也能达到类似的效果,但是节省流量的最好办法还是开启滑块。

费用的话,大部费用是由“客户端请求到边缘加速服务器的流量”和“边缘加速服务器响应给客户端的流量”组成的,而且滑块页面不计入流量。可免费试用。

在开启滑块的情况下,1分钟产生10M流量,基础版包含的50GB可以用3天。标准版(500GB)375元可以用一个月。(以我站实测为例,各站情况不同)。

具体费用在“计费管理-套餐管理-套餐总量 (月)-image.png”查看。超过套餐的流量会使用CDN流量包抵扣。

ECS 获取客户端 IP 的问题有两种解决方案,1. 设置四层代理分析(企业版),2. 设置重定向规则,重定向到直接解析到该网站的另一个域名。

为了尽量减少滑块对用户体验的影响,建议加白名单:ESA-站点-安全防护-WAF-白名单规则,譬如添加省份规则,跳过全部规则(包括滑块)。

其它问题:滑块会拒绝蜘蛛?

其它相似产品:Cloudflare、腾讯云 EdgeOne。


----------------下面是停站维护时显示临时页面的做法----------------

被攻击期借用阿里云 OSS/CDN 显示“维护中”页面的方法。

1.

首先让 AI 快速生成一个维护中的页面,上传到 OSS。

虽然这个文件有一个对应的 CDN 链接,但是域名解析使用“显性 URL”模式并不能正常访问到这个页面。

2.

在阿里云 CDN 添加一个域名(也就是网站域名),会生成一个 CNAME 域名,网站域名 CNAME 到这个域名上。

配置这个 CDN 域名的 OSS 实例、HTTPS 等信息。

这样生效后,访问网站域名就能请求到这个 OSS 上了。

3.

但是它并不像网站一样有默认文档,需要添加重写规则。

打开 CDN-域名管理-缓存配置-重写访问URL,添加,添加重写规则。

例:如果目标页面路径是 https://域名/index.html,那么重写规则就是:

^/(?!.*index\.html$).*$

也就是把所有除 /index.html 以外的路径全部重写到 /index.html。

4.

下一步只要观察这个域名的实时流量和带宽,如果攻击停止了,将域名解析回 ECS。

CDN-统计分析-实时监控-访问数据-选择域名-查询。

xoyozo 22 天前
168

查询路径:阿里云控制台 - 费用与成本 - 订购订单 - 企业服务产品订单

查询网址:https://billing-cost.console.aliyun.com/order/list/enterprise/paid

xoyozo 3 个月前
636

.NET 项目发布到 Linux / CentOS / nginx 上,调用 RedirectToAction 方法跳转到 127.0.0.1:443,而不是正在访问的域名,怎么办?

打开该网站的 nginx 配置文件,找到反射代理配置(proxy_pass),将:

proxy_set_header Host 127.0.0.1:$server_port;

改为

proxy_set_header Host $host;


xoyozo 5 个月前
3,815

早前记录过在 CentOS 中部署 ASP.NET Core 网站,现在宝塔面板已经直接支持创建 .NET 网站了,再次记录一下。


本文环境:VS2022、.NET 9、宝塔面板v11。


一、在 VS 中创建一个 .NET 9 网站,项目名称例:WebApplication1

发布选项:

image.png

关于“生成单个文件”选项,若勾选,发布后的项目启动文件不带后缀名(.dll),尝试在宝塔面板 v11.0.0 中无法顺利启动。


二、在 Linux 服务器上创建目录:/www/wwwroot/WebApplication1/

将发布后的文件上传到这个目录上,最终的文件结构如下:

image.png


三、进入宝塔面板,在 网站-Net项目 中安装 .Net环境管理,这里以 9.0.201 为例:

image.png


四、添加项目

项目名称:随意

运行路径:项目所在目录,本例中为:

/www/wwwroot/WebApplication1

启动命令:使用 dotnet 命令,dotnet 命令可以不使用全路径(/www/server/dotnet/9.0.201/dotnet),第一个参数是项目启动文件,--urls 是反向代理的服务器和端口。服务器名可以是*也可以是localhost。例:

dotnet WebApplication1.dll --urls=http://*:5000

项目端口:与启动命令中的端口号一致

开机启动:一般会勾选

启动用户:尽量用 www,最小权限原则。

image.png

正常情况下,网站已启动,如果未启动,检查配置,根据报错内容排查问题。


五、配置网站

添加域名、SSL 证书等。


友情提示:

  • 网站版本更新重新发布后,需要手动重启网站才能生效,习惯于发布到 IIS(会自动生效)的同学要特别注意。

  • 新手尽量以空项目或默认项目来部署,避免因特殊原因导致一系列其它问题。

  • nginx 反向代理并不会转发所有 Header,需要手动配置。

xoyozo 5 个月前
7,131

nginx.conf 中使用 resolver 设置了 DNS 后,nginx 会遵循这个指令,而不是直接使用系统的 hosts 配置。

所以,如果 resolver 设置了外部 DNS(譬如一般的公共 DNS),在 access_by_lua_block 中使用 resty.http 库发起对包含域名的网址的请求,会忽略 hosts 的设置。

解决方案:

1、修改 resolver 指向为本机 DNS。(AI 推荐,实测无效,可以研究一下配合 dnsmasq 使读取 hosts)

查看本机 DNS 的命令:

cat /etc/resolv.conf


nmcli dev show | grep DNS

2、request_uri 中直接请求带 IP 地址的网址。

要求这个网站允许直接使用 IP 地址访问。

需要禁用 SSL 验证(ssl_verify = false)。

xoyozo 5 个月前
3,886

AutoUpdater.NET 是一个开源库,专为 .NET 桌面应用程序设计,支持 Windows Forms 和 WPF 应用。它通过从服务器获取 XML 文件来检测新版本信息,当发现新版本时向用户显示更新对话框。

相对于 ClickOnce,AutoUpdater.NET 的配置更简单一些。

首先通过 NuGet 包管理器安装 Autoupdater.NET.Official,然后在应用程序入口点添加以下代码:

AutoUpdater.Start("http://yourserver.com/path/to/update.xml");

XML 文件结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<item>
  <version>2.0.0.0</version> <!--必填:最新版本号-->
  <url>http://yourserver.com/path/to/updatefile.zip</url> <!--必填:更新文件下载地址-->
  <changelog>http://yourserver.com/path/to/changelog.txt</changelog> <!--可选:更新日志-->
  <mandatory>False</mandatory> <!--可选:是否强制更新-->
</item>

Windows Forms 在 Program.cs 文件的 Main() 方法中,WPF 在 App.xaml.cs 的 OnStartup() 中添加:

AutoUpdater.Start("http://yourserver.com/path/to/update.xml");
AutoUpdater.CheckForUpdateEvent += (e) =>
{
    if (e.Error != null)
    {
        MessageBox.Show($"检查版本更新失败:{e.Error.Message}");
    }
    if (e.IsUpdateAvailable)
    {
        if (e.Mandatory.Value)
        {
            // 强制更新
            AutoUpdater.DownloadUpdate(e);
        }
        else
        {
            // 可选更新
            if (MessageBox.Show("发现新版本,是否立即更新?", "更新提示", MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
            {
                AutoUpdater.DownloadUpdate(e);
            }
        }
    }
};

这样就能简单实现打开应用时判断是否有更新。具体用法参:GitHub

对于控制台应用程序,AutoUpdater.NET 并不直接支持。可以使用 GeneralUpdate 等轻量级自动更新库。

其它:

  • 若希望通过标准安装流程(如添加到开始菜单),优先选择 ClickOnce,适合长期维护的内部工具。

  • 若追求快速集成和无感更新,AutoUpdater.NET 更灵活。

  • 无论哪种方案,务必对程序进行代码签名(如购买企业证书或生成测试证书),否则系统可能拦截安装。(你要允许来自未知发布者的此应用对你的设备进行更改吗)

  • 可以购买“OV 代码签名”证书或“EV 代码签名”证书,注意:“代码签名证书”与“域名证书”互不通用。

xoyozo 6 个月前
7,033

前几天实现了在 nginx 中使用 lua 实现远程鉴权,今天想试试在 IIS 中能不能实现相同的功能。查询资料发现需要使用 URL 重写和 HTTP 请求模块,没有深究。干脆使用 ASP.NET 中间件来实现吧。

在 StratUp.cs 的 Configure 方法中,或 Program.cs 文件中添加以下代码:

// 远程鉴权
app.Use(async (context, next) =>
{
    var ip = context.Connection.RemoteIpAddress!.ToString();
    var ua = context.Request.Headers.UserAgent.ToString();
    var host = context.Request.Host.Host;
    var uri = new Uri(context.Request.GetDisplayUrl()).PathAndQuery;

    var client = new HttpClient();
    client.Timeout = TimeSpan.FromSeconds(1); // 设置超时时间

    try
    {
        var requestUrl = "https://鉴权地址/";

        var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUrl);
        requestMessage.Headers.Add("X-Real-IP", ip);
        requestMessage.Headers.Add("User-Agent", ua);
        requestMessage.Headers.Add("X-Forwarded-Host", host);
        requestMessage.Headers.Add("X-Forwarded-Uri", uri);

        // 发送请求
        var response = await client.SendAsync(requestMessage);

        // 检查响应状态码
        if (response.StatusCode == HttpStatusCode.Forbidden)
        {
            // 如果返回403,则拒绝访问
            context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
            await context.Response.WriteAsync("Access Denied");
        }
        else
        {
            // 如果返回其他状态码,则继续执行管道中的下一个中间件
            await next();
        }
    }
    catch (TaskCanceledException ex) when (ex.CancellationToken.IsCancellationRequested)
    {
        // 如果请求超时(任务被取消),则继续执行管道中的下一个中间件
        await next();
    }
    catch
    {
        // 如果遇到错误,则继续执行管道中的下一个中间件
        await next();
    }
});

代码很简单,使用 HttpClient 发送请求,若返回 403 则拒绝访问,其它情况继续执行业务逻辑,超时或报错的情况按需修改即可。

若鉴权接口在私网中,建议将鉴权接口域名和私网 IP 添加到 hosts 文件中。

xoyozo 1 年前
1,186
  1. 使 lua 支持 resty.http

  2. 在 access_by_lua_block 代码块中实现远程鉴权:

    #鉴权-START
    #resolver 223.5.5.5; # cat /etc/resolv.conf
    access_by_lua_block {
        local http = require("resty.http")
        local httpc = http.new()
        httpc:set_timeout(500)  -- 连接超时
        local res, err = httpc:request_uri("https://鉴权地址/", {
            method = "GET",
            headers = {
                ["X-Real-IP"] = ngx.var.remote_addr,
                ["User-Agent"] = ngx.var.http_user_agent,
                ["X-Forwarded-Host"] = ngx.var.host,
                ["X-Forwarded-Uri"] = ngx.var.request_uri,
            },
            ssl_verify = false, -- 禁用 SSL 验证
            timeout = 500,     -- 读取超时
        })
    
        if not res then
            ngx.log(ngx.ERR, "Failed to request: " .. err)
        end
            
        if res and res.status == 403 then
            ngx.exit(ngx.HTTP_FORBIDDEN)
            -- return ngx.redirect("https://一个显示403友好信息的页面.html")
        end
    }
    #鉴权-END

    注意更改接口地址和友情显示 403 页面地址。

    本示例仅捕获 403 状态码,500、408 等其它异常情况视为允许访问,请根据业务需求自行添加状态码的判断。

    若超时也会进入 if not res then 代码块。

    建议将此代码部署在 nginx 主配置文件的 http 代码块中(宝塔面板中的路径:/www/server/nginx/nginx/conf/nginx.conf),如果你只想为单个网站鉴权,也可以放在网站配置文件的 server 块中。

  3. 若鉴权接口在私网中,建议将鉴权接口域名和私网 IP 添加到 hosts 文件中。


  1. 直接输出字符串

    ngx.header.content_type = "text/plain";
    ngx.say("hello world!")
  2. 输出到日志

    ngx.log(ngx.ERR, "Response status: " .. res.status)

    日志在网站的 站名.error.log 中查看。

    宝塔面板查看方式:日志 - 网站日志 - 异常

  3. 若想获取服务器 CPU 使用率等信息并传递给远程鉴权接口,请参考此文

  4. 常见问题

    no resolver defined to resolve

    原因:没有定义 DNS 解析器

    解决方法:在 http 块或 server 块中添加 resolver 8.8.8.8 valid=30s;,推荐使用接入商自己的公共 DNS,如果走内网,推荐使用本机 DNS

    unable to get local issuer certificate

    原因:没有配置 SSL 证书信息

    解决方法:添加 request_uri 参数:

    ssl_verify = true,  -- 启用 SSL 验证
    ssl_trusted_certificate = "证书路径",  -- 指定 CA 证书路径

    ssl_verify = false,  -- 禁用 SSL 验证
  5. 若您不想用 lua,可以用 nginx 原生自带的  auth_request 模块来实现

xoyozo 1 年前
2,793
引擎连接方式
mysqlimysqli_connect("域名或IP:端口", "用户名", '密码', "数据库名")
Scaffold-DbContextScaffold-DbContext "server=域名或IP;port=端口;uid=用户名;pwd=密码;database=数据库名;" Pomelo.EntityFrameworkCore.MySql -OutputDir 模型路径 -Force

如果端口配置不正确,会报错:

Unable to connect to any of the specified MySQL hosts.

xoyozo 1 年前
934

鉴权方式有许多,譬如可以用 lua 的 access_by_lua 来实现,这里用 nginx 自带的 auth_request,虽然功能简单,但效率更高。

第一步,确保 nginx 已编译安装 auth_request 模块,见此文

第二步,打开需要鉴权的网站的 nginx 配置文件,添加以下代码块:

    #鉴权-START
    location / {
        auth_request /auth;
        error_page 403 = @error403;
        
        #PHP-INFO-START  PHP引用配置,可以注释或修改
        include enable-php-**.conf;
        #PHP-INFO-END
    }
    location = /auth {
        internal;
        proxy_pass https://鉴权地址;
        proxy_pass_request_body off;
        proxy_set_header Content-Length "";
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header User-Agent $http_user_agent;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Uri $request_uri;
        proxy_intercept_errors on;
        #proxy_read_timeout 1s; # 超时会报 500
    }
    location @error403 {
        #default_type text/plain;
        #return 403 'forbidden';
        return 302 https://一个显示403友好信息的页面.html;
    }
    #鉴权-END

一般放在所有的 location 之前。

这里自定义请求头 X-Forwarded-HostX-Forwarded-Uri 用来传递 host 与 uri。API 应从 Header 中相应取值。

宝塔面板中是通过 include enable-php-**.conf; 的方式调用 PHP ,那么可以将此行移入上面的 location / 代码块中,因为此代码块能匹配所有的请求路径。

最后,若鉴权接口在私网中,将鉴权接口域名和私网 IP 添加到 hosts 文件中。

xoyozo 1 年前
1,541