- 会话 cookie 增加 Secure 标志;新增 [web].cookie_secure 配置 (默认 true,仅本地 HTTP 调试关闭;缺失字段按安全默认处理) - SMTP/IMAP/POP3 认证接入封禁体系(store.RecordAuthFailure 与 Web 共用 ban_entries):失败计数达 ban.max_fail_attempts 即封禁 IP, 已封禁 IP 拒绝认证,堵住协议层暴力破解 - 附件存储路径遍历防护重写:FullPath 白名单校验(UUID 文件名格式) + baseDir 前缀兜底,非法路径返回错误;Save 扩展名白名单化 - 初始管理员不再使用 admin/admin:密码取 MAILGO_ADMIN_PASSWORD 或 随机生成并打印一次;新增 MustChangePassword 首登强制改密 (管理员重置密码同样触发) - 外发中继默认验证 TLS 证书(保护 AUTH 凭据,防 MITM),直投 MX 保持机会式 TLS;新增 outbound.relay_tls_insecure 开关(默认 false) - 新增安全响应头中间件:HSTS、X-Frame-Options DENY、nosniff、 Referrer-Policy、基础 CSP(frame-ancestors 'none' 防点击劫持, connect-src/form-action 'self' 防数据外泄) - LDAP/OAuth 登录错误统一为通用文案,原始错误只写日志, 不再回显邮箱/内部细节(防用户枚举与信息泄露) - 新增 25 个回归测试:cookie 标志、封禁阈值、路径遍历用例、 中继 TLS 验证(自签证书 STARTTLS 集成)、安全头、OAuth 文案 部署注意:升级后所有会话失效需重新登录;若直接以 HTTP 提供 服务需显式配置 cookie_secure = false。
79 lines
2.1 KiB
Go
79 lines
2.1 KiB
Go
package imap_server
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"fmt"
|
|
"log"
|
|
|
|
"mail_go/config"
|
|
"mail_go/internal/store"
|
|
"mail_go/internal/tlsutil"
|
|
|
|
"github.com/emersion/go-imap/backend"
|
|
imapserver "github.com/emersion/go-imap/server"
|
|
)
|
|
|
|
// IMAPServer wraps a go-imap Server and provides mailbox access capability.
|
|
type IMAPServer struct {
|
|
stores *store.Stores
|
|
cfg config.IMAPConfig
|
|
banCfg config.BanConfig
|
|
tlsLoader *tlsutil.Loader
|
|
}
|
|
|
|
// NewIMAPServer creates a new IMAP server instance. tlsLoader may be nil
|
|
// when TLS is not configured.
|
|
func NewIMAPServer(cfg config.IMAPConfig, stores *store.Stores, tlsLoader *tlsutil.Loader, banCfg config.BanConfig) *IMAPServer {
|
|
return &IMAPServer{
|
|
stores: stores,
|
|
cfg: cfg,
|
|
banCfg: banCfg,
|
|
tlsLoader: tlsLoader,
|
|
}
|
|
}
|
|
|
|
func (s *IMAPServer) tlsConfig() (*tls.Config, error) {
|
|
if s.tlsLoader == nil {
|
|
return nil, fmt.Errorf("IMAP TLS certificate or key not configured")
|
|
}
|
|
// GetCertificate 每次握手按需重载证书,证书更新后无需重启服务
|
|
return &tls.Config{GetCertificate: s.tlsLoader.GetCertificate}, nil
|
|
}
|
|
|
|
// newServer creates a configured imapserver.Server with the given address.
|
|
func (s *IMAPServer) newServer(addr string, tlsConfig *tls.Config) *imapserver.Server {
|
|
be := &imapBackend{stores: s.stores, banCfg: s.banCfg}
|
|
srv := imapserver.New(be)
|
|
srv.Addr = addr
|
|
srv.TLSConfig = tlsConfig
|
|
srv.AllowInsecureAuth = tlsConfig == nil
|
|
return srv
|
|
}
|
|
|
|
// Start starts the IMAP server on the plain-text port.
|
|
func (s *IMAPServer) Start() error {
|
|
tlsConfig, err := s.tlsConfig()
|
|
if err != nil {
|
|
log.Printf("IMAP STARTTLS 未启用: %v", err)
|
|
}
|
|
srv := s.newServer(s.cfg.Addr, tlsConfig)
|
|
log.Printf("IMAP server listening on %s", s.cfg.Addr)
|
|
return srv.ListenAndServe()
|
|
}
|
|
|
|
// StartTLS starts the IMAP server on the TLS port.
|
|
func (s *IMAPServer) StartTLS() error {
|
|
tlsConfig, err := s.tlsConfig()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
srv := s.newServer(s.cfg.TLSAddr, tlsConfig)
|
|
|
|
log.Printf("IMAPS server listening on %s", s.cfg.TLSAddr)
|
|
return srv.ListenAndServeTLS()
|
|
}
|
|
|
|
// ensure imapBackend satisfies backend.Backend at compile time
|
|
var _ backend.Backend = (*imapBackend)(nil)
|