You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Croppie向Laravel 8控制器上传裁剪图片时出现403错误

解决Laravel + Croppie提交裁剪图触发WAF 403错误的方案

问题根源

Croppie生成的base64格式图片数据中,可能包含了Atomicorp WAF规则(ID 340029)所匹配的命令关键字组合(比如规则里的curl、python等字符串的base64编码变体),导致WAF误判为命令注入攻击,返回403。

解决方案

1. 改用Blob + FormData提交(推荐,彻底避免误判)

放弃用隐藏input存储base64字符串,改用Blob格式通过FormData以文件上传的方式提交,这是标准的文件传输方式,不会触发WAF的命令注入检测。

前端代码修改:

// 生成裁剪图时获取Blob对象
$('.upload-result').on('click', function(ev) {
    $uploadCrop.croppie('result', {
        type: 'blob', // 将类型改为blob
        size: {width: 1920, height: 1280},
        format: 'jpeg',
        quality: 0.7
    }).then(function(blob) {
        // 更新预览图
        $('#imgPreview').removeClass('d-none');
        $('#imgPreview').attr("src", URL.createObjectURL(blob));
        
        // 将Blob对象暂存到全局变量,供提交时使用
        window.croppedImageBlob = blob;
    });
});

// 拦截表单默认提交,改用AJAX发送FormData
$('#submitBtn').on('click', function(e) {
    e.preventDefault();
    
    const formData = new FormData();
    // 添加CSRF令牌
    formData.append('_token', $('input[name="_token"]').val());
    // 添加标题字段
    formData.append('title', $('#title').val());
    // 添加裁剪后的图片Blob,指定文件名
    formData.append('img_crop', window.croppedImageBlob, 'cropped-card.jpg');
    
    $.ajax({
        url: "{{ route('card.store') }}",
        type: 'POST',
        data: formData,
        processData: false, // 禁止jQuery处理FormData
        contentType: false, // 自动设置正确的Content-Type
        success: function(res) {
            // 处理成功逻辑,比如跳转至列表页
            window.location.href = "{{ route('card.index') }}";
        },
        error: function(xhr) {
            console.error('提交失败:', xhr.responseText);
        }
    });
});

Laravel控制器修改:

现在可以像处理普通上传文件一样获取图片:

public function store(Request $request)
{
    $request->validate([
        'title' => 'required|string|max:255',
        'img_crop' => 'required|image|mimes:jpeg,png|max:2048', // 根据需求调整验证规则
    ]);
    
    // 存储图片到public磁盘
    $imagePath = $request->file('img_crop')->store('card-images', 'public');
    
    // 后续逻辑:创建卡片记录等
    // Card::create([
    //     'title' => $request->title,
    //     'image_path' => $imagePath,
    // ]);
    
    return response()->json(['success' => true]);
}

2. 调整WAF规则(需服务器权限)

如果有权限操作服务器防火墙,可以针对提交路由排除误判的规则:

  • 若使用Apache + ModSecurity,在虚拟主机配置中添加:
    <Location "{{ route('card.store') }}">
        SecRuleRemoveById 340029
    </Location>
    
  • 若使用Nginx + ModSecurity,在对应的server块中添加:
    location = "{{ route('card.store') }}" {
        modsecurity_rules 'SecRuleRemoveById 340029';
    }
    
  • 或者联系服务器管理员,说明这是误判,请求针对该路由放行340029规则。

3. 临时方案:对base64字符串转义编码

如果暂时无法修改前端或WAF规则,可以对base64字符串进行URL编码,避免触发规则:

前端代码:

$('.upload-result').on('click', function(ev) {
    $uploadCrop.croppie('result', {
        type: 'canvas',
        size: {width: 1920, height: 1280},
        format: 'jpeg',
        quality: 0.7
    }).then(function(resp) {
        // 对base64字符串进行URL编码
        const encodedData = encodeURIComponent(resp);
        $('#imgCrop').val(encodedData);
        // 预览时需解码
        $('#imgPreview').removeClass('d-none');
        $('#imgPreview').attr("src", decodeURIComponent(encodedData));
    });
});

Laravel控制器解码:

public function store(Request $request)
{
    $request->validate([
        'title' => 'required|string',
        'img_crop' => 'required|string',
    ]);
    
    // 解码URL编码的base64字符串
    $decodedData = urldecode($request->img_crop);
    // 移除base64前缀,解码为图片数据
    $imageData = str_replace('data:image/jpeg;base64,', '', $decodedData);
    $imageData = base64_decode($imageData);
    
    // 存储图片到文件
    $fileName = uniqid() . '.jpg';
    Storage::disk('public')->put('card-images/' . $fileName, $imageData);
    
    // 后续逻辑...
}

注意:此方案仍有小概率被WAF拦截,仅作为临时过渡方案。

内容的提问来源于stack exchange,提问作者Stefan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:56:03