🔐 Security & Secrets (GoMT4)¶
This page explains how to handle credentials and protect your setup based on the current GoMT4 codebase (Windows, local MT4 terminal, gRPC on 127.0.0.1:50051).
TL;DR: keep secrets out of Git, prefer per‑machine env vars or Windows Credential Manager, lock down the gRPC port, and redact logs.
🧭 Scope & threat model¶
- Default setup: gRPC server listens on localhost only → attacks must come from the same PC.
- If you expose it to LAN/WAN (not default): you must add TLS and authentication (see ▶ Optional hardening).
🗝️ Secrets inventory (what we actually store)¶
- MT4 login (account number)
- MT4 password (investor or trade)
- MT4 server (e.g.,
RoboForex-Demo) - Optional symbols list / defaults (not sensitive)
In your repo these live in examples/config/config.json (dev) or env vars (recommended).
📁 Where to store secrets¶
1) Development (recommended)¶
- Create
.envin repo root (ignored by Git) and let VS Code inject it (vialaunch.json→envFile). - Commit only
.env.example(placeholder values).
.env.example
MT4_LOGIN=12345678
MT4_PASSWORD=replace-me
MT4_SERVER=YourBroker-Server
DEFAULT_SYMBOL=EURUSD
.gitignore (fragment)
# Secrets
.env
examples/config/config.local.json
Why: the real .env never leaves your machine; teammates create their own.
2) Production / headless¶
-
Prefer per‑machine environment variables (user scope):
-
PowerShell (current user):
* Or use Windows Credential Manager and load at runtime (requires a small helper; see ▶ Optional hardening).[Environment]::SetEnvironmentVariable("MT4_PASSWORD","<secret>","User")
3) JSON config¶
examples/config/config.jsonis convenient but do not commit real credentials. Use a local variant (config.local.json) in.gitignore.
🔒 Process & file permissions (Windows)¶
- Run GoMT4 under a standard user, not Administrator.
- Keep repo and MT4 data folders in user profile; avoid world‑writable paths.
- NTFS permissions: only your user needs read access to
.envand local configs.
🧱 Network exposure¶
- Keep the listener on
127.0.0.1:50051for local dev. - The firewall rule you created opens the port inbound; limit it to Local subnet or remove it if not required for local‑only.
- If you must listen on
0.0.0.0or a LAN IP: enable TLS and some auth (token or mTLS). See below.
📝 Logging hygiene¶
- Never log credentials or full requests. Redact sensitive fields.
Redaction helper (Go)
func redact(v string) string {
if len(v) <= 4 { return "***" }
return v[:2] + strings.Repeat("*", len(v)-4) + v[len(v)-2:]
}
// log.Printf("login=%d server=%s pwd=%s", login, server, redact(password))
- When printing orders/quotes, it’s fine; avoid dumping entire structs that may include headers/metadata.
🔗 Dependencies & supply chain¶
- You import pb as a Go module:
git.mtapi.io/root/mrpc-proto/mt4/libraries/go. - Pin versions: use tags/commits in
go.mod, keepgo.sumcommitted. Example:
require git.mtapi.io/root/mrpc-proto/mt4/libraries/go v0.1.3
go mod vendor; this copies deps into vendor/ (bigger repo, but no network at build time).
🧪 Secrets in tests & examples¶
- Don’t embed real credentials in
main.goor examples; read from env/config. - Add a quick startup guard:
if os.Getenv("MT4_PASSWORD") == "replace-me" {
log.Fatal("Refusing to start with placeholder password — set MT4_PASSWORD")
}
✅ Checklist (quick)¶
-
.envexists locally;.env.examplein Git; real.envis ignored. - No real secrets in
config.jsoncommitted. - Logs redact passwords/tokens.
- gRPC bound to 127.0.0.1 unless TLS+auth is configured.
-
go.modpins pb module;go.sumcommitted.
▶ Optional hardening (when exposing beyond localhost)¶
TLS for gRPC¶
Not enabled by default in examples. Enable if you bind to non‑localhost.
-
Generate a server cert (self‑signed for lab):
-
PowerShell:
* Export PFX/CRT/KEY and configure your server to use it. * In Go server, add:New-SelfSignedCertificate -DnsName "gomt4.local" -CertStoreLocation Cert:\LocalMachine\My
creds := credentials.NewTLS(&tls.Config{ /* MinVersion: tls.VersionTLS12, Certificates: [...] */ })
s := grpc.NewServer(grpc.Creds(creds))
- In client, trust the CA or use
RootCAswith the server cert.
Simple token auth (metadata header)¶
Not present in your current examples. Add only if you need LAN/WAN.
- Client adds header:
md := metadata.Pairs("x-api-key", os.Getenv("GOMT4_API_KEY"))
ctx := metadata.NewOutgoingContext(ctx, md)
- Server interceptor checks it:
func apiKeyUnary(next grpc.UnaryHandler) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
if md, ok := metadata.FromIncomingContext(ctx); ok {
if keys := md.Get("x-api-key"); len(keys) == 1 && keys[0] == os.Getenv("GOMT4_API_KEY") {
return handler(ctx, req)
}
}
return nil, status.Error(codes.Unauthenticated, "invalid api key")
}
}
Windows Credential Manager¶
Optional replacement for
.envin production.
- Store a Generic Credential (name
GoMT4/MT4_PASSWORD). - Load via a small helper lib (e.g.,
github.com/danieljoos/wincred).
🔍 Quick self‑audit before push¶
- Grep for forbidden strings:
Select-String -Path . -Pattern "Password=", "MT4_PASSWORD", "x-api-key" -NotMatch "\.env$" -Recurse
.gitignore catches .env and any *.local.json.
📎 References¶
- Cookbook →
ConfigExample.md(how to structure dev configs) - Setup →
setup.md(launch.json withenvFile) - Performance Notes → logging hints (hot paths)