ccjk 14.2.2 → 15.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +75 -338
- package/dist/cli.js +89 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/detect.js +15 -0
- package/dist/commands/detect.js.map +1 -0
- package/dist/commands/doctor.js +68 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/git-install.js +50 -0
- package/dist/commands/git-install.js.map +1 -0
- package/dist/commands/init.js +165 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/mcp.js +66 -0
- package/dist/commands/mcp.js.map +1 -0
- package/dist/commands/menu.js +42 -0
- package/dist/commands/menu.js.map +1 -0
- package/dist/commands/profile.js +138 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/core/detect.js +24 -0
- package/dist/core/detect.js.map +1 -0
- package/dist/core/lint.js +49 -0
- package/dist/core/lint.js.map +1 -0
- package/dist/core/mcp.js +41 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/paths.js +9 -0
- package/dist/core/paths.js.map +1 -0
- package/dist/core/profiles.js +104 -0
- package/dist/core/profiles.js.map +1 -0
- package/dist/core/providers.js +53 -0
- package/dist/core/providers.js.map +1 -0
- package/dist/core/settings.js +31 -0
- package/dist/core/settings.js.map +1 -0
- package/dist/core/slash-templates.js +56 -0
- package/dist/core/slash-templates.js.map +1 -0
- package/dist/core/tools.js +27 -0
- package/dist/core/tools.js.map +1 -0
- package/package.json +43 -164
- package/README.HONEST.md +0 -176
- package/README.en.md +0 -67
- package/README.ja.md +0 -67
- package/README.ko.md +0 -67
- package/README.zh-CN.md +0 -86
- package/bin/ccjk.mjs +0 -5
- package/bin/ccjk.ts +0 -222
- package/dist/chunks/agent-teams.mjs +0 -145
- package/dist/chunks/agent.mjs +0 -1439
- package/dist/chunks/agents.mjs +0 -3783
- package/dist/chunks/api-cli.mjs +0 -135
- package/dist/chunks/api-config-selector.mjs +0 -159
- package/dist/chunks/api-providers.mjs +0 -144
- package/dist/chunks/api.mjs +0 -115
- package/dist/chunks/auto-bootstrap.mjs +0 -358
- package/dist/chunks/auto-fixer.mjs +0 -95
- package/dist/chunks/auto-updater.mjs +0 -507
- package/dist/chunks/banner.mjs +0 -173
- package/dist/chunks/bash.mjs +0 -187
- package/dist/chunks/boost.mjs +0 -474
- package/dist/chunks/brain-config.mjs +0 -75
- package/dist/chunks/brain-status.mjs +0 -89
- package/dist/chunks/ccjk-agents.mjs +0 -416
- package/dist/chunks/ccjk-all.mjs +0 -1046
- package/dist/chunks/ccjk-config.mjs +0 -445
- package/dist/chunks/ccjk-hooks.mjs +0 -1074
- package/dist/chunks/ccjk-mcp.mjs +0 -763
- package/dist/chunks/ccjk-setup.mjs +0 -765
- package/dist/chunks/ccjk-skills.mjs +0 -518
- package/dist/chunks/ccr.mjs +0 -109
- package/dist/chunks/ccu.mjs +0 -40
- package/dist/chunks/check-updates.mjs +0 -117
- package/dist/chunks/claude-code-incremental-manager.mjs +0 -761
- package/dist/chunks/claude-config.mjs +0 -606
- package/dist/chunks/claude-config2.mjs +0 -62
- package/dist/chunks/claude-wrapper.mjs +0 -85
- package/dist/chunks/clavue-config.mjs +0 -1454
- package/dist/chunks/cleanup-migration.mjs +0 -20
- package/dist/chunks/cli-hook.mjs +0 -4096
- package/dist/chunks/cloud-sync.mjs +0 -29
- package/dist/chunks/code-type-resolver.mjs +0 -880
- package/dist/chunks/codex-config-switch.mjs +0 -452
- package/dist/chunks/codex-provider-manager.mjs +0 -238
- package/dist/chunks/codex-uninstaller.mjs +0 -404
- package/dist/chunks/codex.mjs +0 -2141
- package/dist/chunks/commands.mjs +0 -108
- package/dist/chunks/commands2.mjs +0 -421
- package/dist/chunks/commit.mjs +0 -140
- package/dist/chunks/completion.mjs +0 -517
- package/dist/chunks/config-consolidator.mjs +0 -172
- package/dist/chunks/config-switch.mjs +0 -334
- package/dist/chunks/config.mjs +0 -558
- package/dist/chunks/config2.mjs +0 -484
- package/dist/chunks/config3.mjs +0 -486
- package/dist/chunks/constants.mjs +0 -323
- package/dist/chunks/context-opt.mjs +0 -444
- package/dist/chunks/context.mjs +0 -974
- package/dist/chunks/dashboard.mjs +0 -481
- package/dist/chunks/doctor.mjs +0 -1301
- package/dist/chunks/eval.mjs +0 -502
- package/dist/chunks/evolution.mjs +0 -322
- package/dist/chunks/features.mjs +0 -715
- package/dist/chunks/fish.mjs +0 -181
- package/dist/chunks/fs-operations.mjs +0 -180
- package/dist/chunks/health-alerts.mjs +0 -830
- package/dist/chunks/help.mjs +0 -341
- package/dist/chunks/hook-installer.mjs +0 -48
- package/dist/chunks/impact.mjs +0 -651
- package/dist/chunks/index.mjs +0 -23
- package/dist/chunks/index10.mjs +0 -19
- package/dist/chunks/index11.mjs +0 -1171
- package/dist/chunks/index12.mjs +0 -218
- package/dist/chunks/index13.mjs +0 -679
- package/dist/chunks/index14.mjs +0 -1009
- package/dist/chunks/index15.mjs +0 -194
- package/dist/chunks/index2.mjs +0 -7637
- package/dist/chunks/index3.mjs +0 -171
- package/dist/chunks/index4.mjs +0 -26
- package/dist/chunks/index5.mjs +0 -19
- package/dist/chunks/index6.mjs +0 -19092
- package/dist/chunks/index7.mjs +0 -616
- package/dist/chunks/index8.mjs +0 -1602
- package/dist/chunks/index9.mjs +0 -5384
- package/dist/chunks/init.mjs +0 -1911
- package/dist/chunks/installer.mjs +0 -757
- package/dist/chunks/installer2.mjs +0 -103
- package/dist/chunks/interview.mjs +0 -2927
- package/dist/chunks/json-config.mjs +0 -60
- package/dist/chunks/linux.mjs +0 -3863
- package/dist/chunks/macos.mjs +0 -69
- package/dist/chunks/main.mjs +0 -635
- package/dist/chunks/manager.mjs +0 -1048
- package/dist/chunks/marketplace.mjs +0 -265
- package/dist/chunks/mcp-cli.mjs +0 -205
- package/dist/chunks/mcp-performance.mjs +0 -187
- package/dist/chunks/mcp.mjs +0 -667
- package/dist/chunks/memory-check.mjs +0 -2973
- package/dist/chunks/memory-paths.mjs +0 -259
- package/dist/chunks/memory-sync.mjs +0 -209
- package/dist/chunks/memory.mjs +0 -354
- package/dist/chunks/metrics-display.mjs +0 -153
- package/dist/chunks/monitor.mjs +0 -1856
- package/dist/chunks/notification.mjs +0 -1864
- package/dist/chunks/onboarding.mjs +0 -386
- package/dist/chunks/package.mjs +0 -3
- package/dist/chunks/paradigm.mjs +0 -74
- package/dist/chunks/permission-manager.mjs +0 -250
- package/dist/chunks/permissions.mjs +0 -265
- package/dist/chunks/persistence-manager.mjs +0 -801
- package/dist/chunks/persistence.mjs +0 -707
- package/dist/chunks/platform.mjs +0 -395
- package/dist/chunks/plugin.mjs +0 -1936
- package/dist/chunks/powershell.mjs +0 -213
- package/dist/chunks/prompts.mjs +0 -244
- package/dist/chunks/providers.mjs +0 -263
- package/dist/chunks/quick-actions.mjs +0 -335
- package/dist/chunks/quick-provider.mjs +0 -755
- package/dist/chunks/quick-setup.mjs +0 -421
- package/dist/chunks/remote.mjs +0 -497
- package/dist/chunks/research.mjs +0 -1904
- package/dist/chunks/rollback.mjs +0 -38
- package/dist/chunks/session-manager.mjs +0 -1371
- package/dist/chunks/session.mjs +0 -878
- package/dist/chunks/sessions.mjs +0 -106
- package/dist/chunks/silent-updater.mjs +0 -396
- package/dist/chunks/simple-config.mjs +0 -122
- package/dist/chunks/skill.mjs +0 -117
- package/dist/chunks/skill2.mjs +0 -9052
- package/dist/chunks/skills-sync.mjs +0 -1343
- package/dist/chunks/skills.mjs +0 -577
- package/dist/chunks/slash-commands.mjs +0 -208
- package/dist/chunks/smart-guide.mjs +0 -247
- package/dist/chunks/snapshot.mjs +0 -58
- package/dist/chunks/startup.mjs +0 -487
- package/dist/chunks/stats.mjs +0 -191
- package/dist/chunks/status.mjs +0 -471
- package/dist/chunks/team.mjs +0 -63
- package/dist/chunks/thinking.mjs +0 -626
- package/dist/chunks/trace.mjs +0 -57
- package/dist/chunks/uninstall.mjs +0 -852
- package/dist/chunks/update.mjs +0 -174
- package/dist/chunks/upgrade-manager.mjs +0 -204
- package/dist/chunks/upgrade.mjs +0 -133
- package/dist/chunks/version-checker.mjs +0 -891
- package/dist/chunks/vim.mjs +0 -903
- package/dist/chunks/windows.mjs +0 -14
- package/dist/chunks/workflows.mjs +0 -633
- package/dist/chunks/wsl.mjs +0 -129
- package/dist/chunks/zero-config.mjs +0 -871
- package/dist/chunks/zsh.mjs +0 -182
- package/dist/cli.d.mts +0 -1
- package/dist/cli.d.ts +0 -1
- package/dist/cli.mjs +0 -2684
- package/dist/i18n/locales/en/agent-teams.json +0 -18
- package/dist/i18n/locales/en/agentBrowser.json +0 -80
- package/dist/i18n/locales/en/agents.json +0 -135
- package/dist/i18n/locales/en/api.json +0 -63
- package/dist/i18n/locales/en/ccjk-agents.json +0 -33
- package/dist/i18n/locales/en/ccjk-all.json +0 -23
- package/dist/i18n/locales/en/ccjk-skills.json +0 -22
- package/dist/i18n/locales/en/ccjk.json +0 -276
- package/dist/i18n/locales/en/ccr.json +0 -65
- package/dist/i18n/locales/en/claude-md.json +0 -73
- package/dist/i18n/locales/en/cli.json +0 -148
- package/dist/i18n/locales/en/cloud-setup.json +0 -31
- package/dist/i18n/locales/en/cloud-sync.json +0 -147
- package/dist/i18n/locales/en/cloud.json +0 -40
- package/dist/i18n/locales/en/cloudPlugins.json +0 -118
- package/dist/i18n/locales/en/codex.json +0 -184
- package/dist/i18n/locales/en/cometix.json +0 -29
- package/dist/i18n/locales/en/common.json +0 -68
- package/dist/i18n/locales/en/config.json +0 -108
- package/dist/i18n/locales/en/configuration.json +0 -236
- package/dist/i18n/locales/en/context.json +0 -85
- package/dist/i18n/locales/en/dashboard.json +0 -78
- package/dist/i18n/locales/en/errors.json +0 -26
- package/dist/i18n/locales/en/evolution.json +0 -54
- package/dist/i18n/locales/en/hooks.json +0 -74
- package/dist/i18n/locales/en/hooksSync.json +0 -133
- package/dist/i18n/locales/en/installation.json +0 -83
- package/dist/i18n/locales/en/interview.json +0 -104
- package/dist/i18n/locales/en/language.json +0 -19
- package/dist/i18n/locales/en/lsp.json +0 -78
- package/dist/i18n/locales/en/marketplace.json +0 -116
- package/dist/i18n/locales/en/mcp.json +0 -180
- package/dist/i18n/locales/en/memory.json +0 -23
- package/dist/i18n/locales/en/menu.json +0 -299
- package/dist/i18n/locales/en/multi-config.json +0 -79
- package/dist/i18n/locales/en/notification.json +0 -307
- package/dist/i18n/locales/en/permissions.json +0 -95
- package/dist/i18n/locales/en/persistence.json +0 -127
- package/dist/i18n/locales/en/plugins.json +0 -146
- package/dist/i18n/locales/en/quick-actions.json +0 -78
- package/dist/i18n/locales/en/registry.json +0 -54
- package/dist/i18n/locales/en/remote.json +0 -93
- package/dist/i18n/locales/en/sandbox.json +0 -44
- package/dist/i18n/locales/en/setup.json +0 -44
- package/dist/i18n/locales/en/shencha.json +0 -14
- package/dist/i18n/locales/en/skills.json +0 -100
- package/dist/i18n/locales/en/skillsSync.json +0 -74
- package/dist/i18n/locales/en/smartGuide.json +0 -49
- package/dist/i18n/locales/en/stats.json +0 -20
- package/dist/i18n/locales/en/subagent.json +0 -69
- package/dist/i18n/locales/en/superpowers.json +0 -117
- package/dist/i18n/locales/en/team.json +0 -7
- package/dist/i18n/locales/en/thinking.json +0 -65
- package/dist/i18n/locales/en/tools.json +0 -42
- package/dist/i18n/locales/en/uninstall.json +0 -56
- package/dist/i18n/locales/en/updater.json +0 -29
- package/dist/i18n/locales/en/vim.json +0 -169
- package/dist/i18n/locales/en/workflow.json +0 -55
- package/dist/i18n/locales/en/workspace.json +0 -108
- package/dist/i18n/locales/zh-CN/agent-teams.json +0 -18
- package/dist/i18n/locales/zh-CN/agentBrowser.json +0 -80
- package/dist/i18n/locales/zh-CN/agents.json +0 -135
- package/dist/i18n/locales/zh-CN/api.json +0 -63
- package/dist/i18n/locales/zh-CN/ccjk-agents.json +0 -33
- package/dist/i18n/locales/zh-CN/ccjk-all.json +0 -23
- package/dist/i18n/locales/zh-CN/ccjk-skills.json +0 -22
- package/dist/i18n/locales/zh-CN/ccjk.json +0 -276
- package/dist/i18n/locales/zh-CN/ccr.json +0 -65
- package/dist/i18n/locales/zh-CN/claude-md.json +0 -73
- package/dist/i18n/locales/zh-CN/cli.json +0 -148
- package/dist/i18n/locales/zh-CN/cloud-setup.json +0 -31
- package/dist/i18n/locales/zh-CN/cloud-sync.json +0 -147
- package/dist/i18n/locales/zh-CN/cloud.json +0 -40
- package/dist/i18n/locales/zh-CN/cloudPlugins.json +0 -118
- package/dist/i18n/locales/zh-CN/codex.json +0 -184
- package/dist/i18n/locales/zh-CN/cometix.json +0 -29
- package/dist/i18n/locales/zh-CN/common.json +0 -68
- package/dist/i18n/locales/zh-CN/config.json +0 -108
- package/dist/i18n/locales/zh-CN/configuration.json +0 -234
- package/dist/i18n/locales/zh-CN/context.json +0 -85
- package/dist/i18n/locales/zh-CN/dashboard.json +0 -78
- package/dist/i18n/locales/zh-CN/errors.json +0 -26
- package/dist/i18n/locales/zh-CN/evolution.json +0 -54
- package/dist/i18n/locales/zh-CN/hooks.json +0 -74
- package/dist/i18n/locales/zh-CN/hooksSync.json +0 -133
- package/dist/i18n/locales/zh-CN/installation.json +0 -83
- package/dist/i18n/locales/zh-CN/interview.json +0 -104
- package/dist/i18n/locales/zh-CN/language.json +0 -19
- package/dist/i18n/locales/zh-CN/lsp.json +0 -78
- package/dist/i18n/locales/zh-CN/marketplace.json +0 -116
- package/dist/i18n/locales/zh-CN/mcp.json +0 -180
- package/dist/i18n/locales/zh-CN/memory.json +0 -23
- package/dist/i18n/locales/zh-CN/menu.json +0 -299
- package/dist/i18n/locales/zh-CN/multi-config.json +0 -79
- package/dist/i18n/locales/zh-CN/notification.json +0 -307
- package/dist/i18n/locales/zh-CN/permissions.json +0 -95
- package/dist/i18n/locales/zh-CN/persistence.json +0 -127
- package/dist/i18n/locales/zh-CN/plugins.json +0 -146
- package/dist/i18n/locales/zh-CN/quick-actions.json +0 -78
- package/dist/i18n/locales/zh-CN/registry.json +0 -54
- package/dist/i18n/locales/zh-CN/remote.json +0 -93
- package/dist/i18n/locales/zh-CN/sandbox.json +0 -44
- package/dist/i18n/locales/zh-CN/setup.json +0 -44
- package/dist/i18n/locales/zh-CN/shencha.json +0 -14
- package/dist/i18n/locales/zh-CN/skills.json +0 -100
- package/dist/i18n/locales/zh-CN/skillsSync.json +0 -74
- package/dist/i18n/locales/zh-CN/smartGuide.json +0 -49
- package/dist/i18n/locales/zh-CN/stats.json +0 -20
- package/dist/i18n/locales/zh-CN/subagent.json +0 -69
- package/dist/i18n/locales/zh-CN/superpowers.json +0 -117
- package/dist/i18n/locales/zh-CN/team.json +0 -7
- package/dist/i18n/locales/zh-CN/thinking.json +0 -65
- package/dist/i18n/locales/zh-CN/tools.json +0 -42
- package/dist/i18n/locales/zh-CN/uninstall.json +0 -56
- package/dist/i18n/locales/zh-CN/updater.json +0 -29
- package/dist/i18n/locales/zh-CN/vim.json +0 -169
- package/dist/i18n/locales/zh-CN/workflow.json +0 -55
- package/dist/i18n/locales/zh-CN/workspace.json +0 -108
- package/dist/index.d.mts +0 -5658
- package/dist/index.d.ts +0 -5658
- package/dist/index.mjs +0 -3732
- package/dist/shared/ccjk.5bEolFrk.mjs +0 -254
- package/dist/shared/ccjk.8oaxX4iR.mjs +0 -90
- package/dist/shared/ccjk.B2U7DsPy.mjs +0 -31
- package/dist/shared/ccjk.B2f-cwUP.mjs +0 -468
- package/dist/shared/ccjk.BAGoDD49.mjs +0 -36
- package/dist/shared/ccjk.BBtCGd_g.mjs +0 -899
- package/dist/shared/ccjk.BFQ7yr5S.mjs +0 -16
- package/dist/shared/ccjk.BLsIiTqO.mjs +0 -449
- package/dist/shared/ccjk.BXv8aYs1.mjs +0 -170
- package/dist/shared/ccjk.BnsY5WxD.mjs +0 -171
- package/dist/shared/ccjk.BoApaI4j.mjs +0 -28
- package/dist/shared/ccjk.Bq8TqZG_.mjs +0 -189
- package/dist/shared/ccjk.BtrioX1Z.mjs +0 -25
- package/dist/shared/ccjk.Bx_rmYfN.mjs +0 -69
- package/dist/shared/ccjk.BzPbSEP2.mjs +0 -115
- package/dist/shared/ccjk.C0WLUnFV.mjs +0 -293
- package/dist/shared/ccjk.C1hANZTu.mjs +0 -19
- package/dist/shared/ccjk.C2jHOZVP.mjs +0 -52
- package/dist/shared/ccjk.CNhnT6uQ.mjs +0 -636
- package/dist/shared/ccjk.COweQ1RR.mjs +0 -5
- package/dist/shared/ccjk.CfKKcvWy.mjs +0 -126
- package/dist/shared/ccjk.Cjgrln_h.mjs +0 -297
- package/dist/shared/ccjk.CoCHVXl3.mjs +0 -3951
- package/dist/shared/ccjk.CwGZSTAK.mjs +0 -319
- package/dist/shared/ccjk.CxpGa6MC.mjs +0 -2724
- package/dist/shared/ccjk.D-magaEx.mjs +0 -763
- package/dist/shared/ccjk.D0g2ABGg.mjs +0 -171
- package/dist/shared/ccjk.D6ycHbak.mjs +0 -270
- package/dist/shared/ccjk.D75wivnp.mjs +0 -142
- package/dist/shared/ccjk.DDL-4C-k.mjs +0 -100
- package/dist/shared/ccjk.DFRPtmK_.mjs +0 -75
- package/dist/shared/ccjk.DMV3x5Sd.mjs +0 -299
- package/dist/shared/ccjk.DZ2LLOa-.mjs +0 -2195
- package/dist/shared/ccjk.DbigonEQ.mjs +0 -698
- package/dist/shared/ccjk.DcMvE7lf.mjs +0 -618
- package/dist/shared/ccjk.DeWpAShp.mjs +0 -1828
- package/dist/shared/ccjk.DhJ1kyDR.mjs +0 -30
- package/dist/shared/ccjk.DlTXS9rP.mjs +0 -224
- package/dist/shared/ccjk.DopKzo3z.mjs +0 -305
- package/dist/shared/ccjk.DsZsc4LR.mjs +0 -1280
- package/dist/shared/ccjk.DuzJZlgj.mjs +0 -418
- package/dist/shared/ccjk.Dxgd2vjc.mjs +0 -444
- package/dist/shared/ccjk.J8YiPsOw.mjs +0 -259
- package/dist/shared/ccjk.KfSWcGlE.mjs +0 -38
- package/dist/shared/ccjk.L7yC58_i.mjs +0 -225
- package/dist/shared/ccjk.MwtjAULc.mjs +0 -1447
- package/dist/shared/ccjk.OJKHVSOb.mjs +0 -2005
- package/dist/shared/ccjk.OTnevPNE.mjs +0 -225
- package/dist/shared/ccjk.RyizuzOI.mjs +0 -21
- package/dist/shared/ccjk.T_cX87dY.mjs +0 -15
- package/dist/shared/ccjk.bQ7Dh1g4.mjs +0 -249
- package/dist/shared/ccjk.gDEDGD_t.mjs +0 -38
- package/dist/shared/ccjk.hoqrwWdN.mjs +0 -333
- package/dist/shared/ccjk.i_vn-9C3.mjs +0 -317
- package/dist/shared/ccjk.lG3ccFjm.mjs +0 -885
- package/dist/shared/ccjk.wLJHO0Af.mjs +0 -244
- package/dist/shared/ccjk.y-a_1vK4.mjs +0 -5127
- package/dist/templates/agents/README.md +0 -78
- package/dist/templates/agents/fullstack-developer.json +0 -70
- package/dist/templates/agents/go-expert.json +0 -69
- package/dist/templates/agents/index.json +0 -64
- package/dist/templates/agents/python-expert.json +0 -69
- package/dist/templates/agents/react-specialist.json +0 -69
- package/dist/templates/agents/testing-automation-expert.json +0 -70
- package/dist/templates/agents/typescript-architect.json +0 -69
- package/dist/templates/claude-code/common/settings.json +0 -109
- package/dist/templates/common/error-prevention.md +0 -267
- package/dist/templates/common/karpathy-baseline.md +0 -83
- package/dist/templates/common/output-styles/zh-CN/carmack-mode.md +0 -381
- package/dist/templates/common/output-styles/zh-CN/codex-rigor-mode.md +0 -114
- package/dist/templates/common/output-styles/zh-CN/dhh-mode.md +0 -265
- package/dist/templates/common/output-styles/zh-CN/evan-you-mode.md +0 -539
- package/dist/templates/common/output-styles/zh-CN/jobs-mode.md +0 -369
- package/dist/templates/common/output-styles/zh-CN/linus-mode.md +0 -135
- package/dist/templates/common/output-styles/zh-CN/uncle-bob-mode.md +0 -221
- package/dist/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +0 -628
- package/dist/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +0 -628
- package/dist/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +0 -187
- package/dist/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +0 -191
- package/dist/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +0 -249
- package/dist/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +0 -277
- package/dist/templates/common/workflow/essential/en/agents/get-current-datetime.md +0 -29
- package/dist/templates/common/workflow/essential/en/agents/init-architect.md +0 -115
- package/dist/templates/common/workflow/essential/en/agents/ui-ux-designer.md +0 -91
- package/dist/templates/common/workflow/essential/en/feat.md +0 -92
- package/dist/templates/common/workflow/essential/en/goal.md +0 -147
- package/dist/templates/common/workflow/essential/en/init-project.md +0 -53
- package/dist/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +0 -29
- package/dist/templates/common/workflow/essential/zh-CN/agents/init-architect.md +0 -115
- package/dist/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +0 -91
- package/dist/templates/common/workflow/essential/zh-CN/feat.md +0 -315
- package/dist/templates/common/workflow/essential/zh-CN/goal.md +0 -146
- package/dist/templates/common/workflow/essential/zh-CN/init-project.md +0 -53
- package/dist/templates/common/workflow/git/en/git-cleanBranches.md +0 -102
- package/dist/templates/common/workflow/git/en/git-commit.md +0 -205
- package/dist/templates/common/workflow/git/en/git-rollback.md +0 -90
- package/dist/templates/common/workflow/git/en/git-worktree.md +0 -276
- package/dist/templates/common/workflow/git/zh-CN/git-cleanBranches.md +0 -102
- package/dist/templates/common/workflow/git/zh-CN/git-commit.md +0 -205
- package/dist/templates/common/workflow/git/zh-CN/git-rollback.md +0 -90
- package/dist/templates/common/workflow/git/zh-CN/git-worktree.md +0 -276
- package/dist/templates/common/workflow/interview/en/interview.md +0 -67
- package/dist/templates/common/workflow/interview/zh-CN/interview.md +0 -67
- package/dist/templates/common/workflow/linearMethod/en/linear-method.md +0 -651
- package/dist/templates/common/workflow/linearMethod/zh-CN/linear-method.md +0 -752
- package/dist/templates/common/workflow/refactoringMaster/en/refactoring-master.md +0 -516
- package/dist/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +0 -812
- package/dist/templates/common/workflow/sixStep/en/workflow.md +0 -83
- package/dist/templates/common/workflow/sixStep/zh-CN/workflow.md +0 -359
- package/dist/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +0 -364
- package/dist/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +0 -366
- package/dist/templates/hooks/README.md +0 -212
- package/dist/templates/hooks/git-workflow-hooks.md +0 -551
- package/dist/templates/hooks/post-test/coverage.json +0 -21
- package/dist/templates/hooks/post-test/summary.json +0 -21
- package/dist/templates/hooks/post-test-coverage.md +0 -434
- package/dist/templates/hooks/pre-commit/eslint.json +0 -22
- package/dist/templates/hooks/pre-commit/prettier.json +0 -22
- package/dist/templates/hooks/pre-commit-black.md +0 -274
- package/dist/templates/hooks/pre-commit-eslint.md +0 -153
- package/dist/templates/hooks/pre-commit-gofmt.md +0 -284
- package/dist/templates/hooks/pre-commit-prettier.md +0 -212
- package/dist/templates/hooks/pre-commit-type-check.md +0 -377
- package/dist/templates/skills/ccjk-init.md +0 -154
- package/dist/templates/skills/ccjk-mcp-setup.md +0 -205
- package/dist/templates/skills/ccjk-troubleshoot.md +0 -228
- package/dist/templates/skills/django-patterns.md +0 -1016
- package/dist/templates/skills/git-workflow.md +0 -748
- package/dist/templates/skills/go-idioms.md +0 -963
- package/dist/templates/skills/index.json +0 -132
- package/dist/templates/skills/nextjs-optimization.md +0 -694
- package/dist/templates/skills/python-pep8.md +0 -852
- package/dist/templates/skills/react-patterns.md +0 -686
- package/dist/templates/skills/rust-patterns.md +0 -1057
- package/dist/templates/skills/security-best-practices.md +0 -1413
- package/dist/templates/skills/testing-best-practices.md +0 -1315
- package/dist/templates/skills/ts-best-practices.md +0 -354
- package/templates/agents/README.md +0 -78
- package/templates/agents/fullstack-developer.json +0 -70
- package/templates/agents/go-expert.json +0 -69
- package/templates/agents/index.json +0 -64
- package/templates/agents/python-expert.json +0 -69
- package/templates/agents/react-specialist.json +0 -69
- package/templates/agents/testing-automation-expert.json +0 -70
- package/templates/agents/typescript-architect.json +0 -69
- package/templates/claude-code/common/settings.json +0 -109
- package/templates/common/error-prevention.md +0 -267
- package/templates/common/karpathy-baseline.md +0 -83
- package/templates/common/output-styles/zh-CN/carmack-mode.md +0 -381
- package/templates/common/output-styles/zh-CN/codex-rigor-mode.md +0 -114
- package/templates/common/output-styles/zh-CN/dhh-mode.md +0 -265
- package/templates/common/output-styles/zh-CN/evan-you-mode.md +0 -539
- package/templates/common/output-styles/zh-CN/jobs-mode.md +0 -369
- package/templates/common/output-styles/zh-CN/linus-mode.md +0 -135
- package/templates/common/output-styles/zh-CN/uncle-bob-mode.md +0 -221
- package/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +0 -628
- package/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +0 -628
- package/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +0 -187
- package/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +0 -191
- package/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +0 -249
- package/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +0 -277
- package/templates/common/workflow/essential/en/agents/get-current-datetime.md +0 -29
- package/templates/common/workflow/essential/en/agents/init-architect.md +0 -115
- package/templates/common/workflow/essential/en/agents/ui-ux-designer.md +0 -91
- package/templates/common/workflow/essential/en/feat.md +0 -92
- package/templates/common/workflow/essential/en/goal.md +0 -147
- package/templates/common/workflow/essential/en/init-project.md +0 -53
- package/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +0 -29
- package/templates/common/workflow/essential/zh-CN/agents/init-architect.md +0 -115
- package/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +0 -91
- package/templates/common/workflow/essential/zh-CN/feat.md +0 -315
- package/templates/common/workflow/essential/zh-CN/goal.md +0 -146
- package/templates/common/workflow/essential/zh-CN/init-project.md +0 -53
- package/templates/common/workflow/git/en/git-cleanBranches.md +0 -102
- package/templates/common/workflow/git/en/git-commit.md +0 -205
- package/templates/common/workflow/git/en/git-rollback.md +0 -90
- package/templates/common/workflow/git/en/git-worktree.md +0 -276
- package/templates/common/workflow/git/zh-CN/git-cleanBranches.md +0 -102
- package/templates/common/workflow/git/zh-CN/git-commit.md +0 -205
- package/templates/common/workflow/git/zh-CN/git-rollback.md +0 -90
- package/templates/common/workflow/git/zh-CN/git-worktree.md +0 -276
- package/templates/common/workflow/interview/en/interview.md +0 -67
- package/templates/common/workflow/interview/zh-CN/interview.md +0 -67
- package/templates/common/workflow/linearMethod/en/linear-method.md +0 -651
- package/templates/common/workflow/linearMethod/zh-CN/linear-method.md +0 -752
- package/templates/common/workflow/refactoringMaster/en/refactoring-master.md +0 -516
- package/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +0 -812
- package/templates/common/workflow/sixStep/en/workflow.md +0 -83
- package/templates/common/workflow/sixStep/zh-CN/workflow.md +0 -359
- package/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +0 -364
- package/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +0 -366
- package/templates/hooks/README.md +0 -212
- package/templates/hooks/git-workflow-hooks.md +0 -551
- package/templates/hooks/post-test/coverage.json +0 -21
- package/templates/hooks/post-test/summary.json +0 -21
- package/templates/hooks/post-test-coverage.md +0 -434
- package/templates/hooks/pre-commit/eslint.json +0 -22
- package/templates/hooks/pre-commit/prettier.json +0 -22
- package/templates/hooks/pre-commit-black.md +0 -274
- package/templates/hooks/pre-commit-eslint.md +0 -153
- package/templates/hooks/pre-commit-gofmt.md +0 -284
- package/templates/hooks/pre-commit-prettier.md +0 -212
- package/templates/hooks/pre-commit-type-check.md +0 -377
- package/templates/skills/basic.hbs +0 -72
- package/templates/skills/ccjk-init.md +0 -154
- package/templates/skills/ccjk-mcp-setup.md +0 -205
- package/templates/skills/ccjk-troubleshoot.md +0 -228
- package/templates/skills/code-refactor.hbs +0 -133
- package/templates/skills/code-review.hbs +0 -141
- package/templates/skills/django-patterns.md +0 -1016
- package/templates/skills/git-workflow.md +0 -748
- package/templates/skills/go-idioms.md +0 -963
- package/templates/skills/index.json +0 -132
- package/templates/skills/nextjs-optimization.md +0 -694
- package/templates/skills/python-pep8.md +0 -852
- package/templates/skills/react-patterns.md +0 -686
- package/templates/skills/rust-patterns.md +0 -1057
- package/templates/skills/security-best-practices.md +0 -1413
- package/templates/skills/testing-best-practices.md +0 -1315
- package/templates/skills/ts-best-practices.md +0 -354
- package/templates/skills/type-fix.hbs +0 -132
|
@@ -1,1413 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: security-best-practices
|
|
3
|
-
description: Common vulnerabilities, input validation, authentication patterns, and security scanning
|
|
4
|
-
description_zh: 常见漏洞、输入验证、身份验证模式和安全扫描
|
|
5
|
-
version: 1.0.0
|
|
6
|
-
category: security
|
|
7
|
-
triggers: ['/security-best-practices', '/security', '/vulnerabilities', '/auth-security']
|
|
8
|
-
use_when:
|
|
9
|
-
- Implementing secure coding practices
|
|
10
|
-
- Conducting security reviews and audits
|
|
11
|
-
- Setting up authentication and authorization
|
|
12
|
-
- Preventing common security vulnerabilities
|
|
13
|
-
use_when_zh:
|
|
14
|
-
- 实现安全编码实践
|
|
15
|
-
- 进行安全审查和审计
|
|
16
|
-
- 设置身份验证和授权
|
|
17
|
-
- 防止常见安全漏洞
|
|
18
|
-
auto_activate: true
|
|
19
|
-
priority: 9
|
|
20
|
-
agents: [security-expert, backend-architect]
|
|
21
|
-
tags: [security, vulnerabilities, authentication, validation, encryption]
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
# Security Best Practices | 安全最佳实践
|
|
25
|
-
|
|
26
|
-
## Context | 上下文
|
|
27
|
-
|
|
28
|
-
Use this skill when implementing secure applications, conducting security reviews, and protecting against common vulnerabilities. Essential for building trustworthy and resilient software systems.
|
|
29
|
-
|
|
30
|
-
在实现安全应用程序、进行安全审查和防范常见漏洞时使用此技能。对于构建可信赖和有弹性的软件系统至关重要。
|
|
31
|
-
|
|
32
|
-
## OWASP Top 10 Vulnerabilities | OWASP 十大漏洞
|
|
33
|
-
|
|
34
|
-
### 1. Injection Attacks | 注入攻击
|
|
35
|
-
|
|
36
|
-
```javascript
|
|
37
|
-
// ✅ Good: SQL Injection Prevention
|
|
38
|
-
const mysql = require('mysql2/promise');
|
|
39
|
-
|
|
40
|
-
// Use parameterized queries
|
|
41
|
-
async function getUserById(userId) {
|
|
42
|
-
const connection = await mysql.createConnection(dbConfig);
|
|
43
|
-
|
|
44
|
-
// Safe: Parameters are properly escaped
|
|
45
|
-
const [rows] = await connection.execute(
|
|
46
|
-
'SELECT * FROM users WHERE id = ?',
|
|
47
|
-
[userId]
|
|
48
|
-
);
|
|
49
|
-
|
|
50
|
-
await connection.end();
|
|
51
|
-
return rows[0];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async function searchUsers(searchTerm) {
|
|
55
|
-
const connection = await mysql.createConnection(dbConfig);
|
|
56
|
-
|
|
57
|
-
// Safe: Using LIKE with parameterized query
|
|
58
|
-
const [rows] = await connection.execute(
|
|
59
|
-
'SELECT id, name, email FROM users WHERE name LIKE ? OR email LIKE ?',
|
|
60
|
-
[`%${searchTerm}%`, `%${searchTerm}%`]
|
|
61
|
-
);
|
|
62
|
-
|
|
63
|
-
await connection.end();
|
|
64
|
-
return rows;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// ✅ Good: NoSQL Injection Prevention (MongoDB)
|
|
68
|
-
const { MongoClient, ObjectId } = require('mongodb');
|
|
69
|
-
|
|
70
|
-
async function getUserByIdMongo(userId) {
|
|
71
|
-
const client = new MongoClient(mongoUrl);
|
|
72
|
-
await client.connect();
|
|
73
|
-
|
|
74
|
-
const db = client.db('myapp');
|
|
75
|
-
const users = db.collection('users');
|
|
76
|
-
|
|
77
|
-
// Safe: Validate and sanitize input
|
|
78
|
-
if (!ObjectId.isValid(userId)) {
|
|
79
|
-
throw new Error('Invalid user ID format');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const user = await users.findOne({ _id: new ObjectId(userId) });
|
|
83
|
-
|
|
84
|
-
await client.close();
|
|
85
|
-
return user;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function searchUsersMongo(searchCriteria) {
|
|
89
|
-
const client = new MongoClient(mongoUrl);
|
|
90
|
-
await client.connect();
|
|
91
|
-
|
|
92
|
-
const db = client.db('myapp');
|
|
93
|
-
const users = db.collection('users');
|
|
94
|
-
|
|
95
|
-
// Safe: Validate search criteria structure
|
|
96
|
-
const allowedFields = ['name', 'email', 'department'];
|
|
97
|
-
const sanitizedCriteria = {};
|
|
98
|
-
|
|
99
|
-
for (const [key, value] of Object.entries(searchCriteria)) {
|
|
100
|
-
if (allowedFields.includes(key) && typeof value === 'string') {
|
|
101
|
-
sanitizedCriteria[key] = { $regex: value, $options: 'i' };
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const users_result = await users.find(sanitizedCriteria).toArray();
|
|
106
|
-
|
|
107
|
-
await client.close();
|
|
108
|
-
return users_result;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ❌ Bad: Vulnerable to SQL injection
|
|
112
|
-
async function vulnerableGetUser(userId) {
|
|
113
|
-
const connection = await mysql.createConnection(dbConfig);
|
|
114
|
-
|
|
115
|
-
// Dangerous: Direct string concatenation
|
|
116
|
-
const query = `SELECT * FROM users WHERE id = ${userId}`;
|
|
117
|
-
const [rows] = await connection.execute(query);
|
|
118
|
-
|
|
119
|
-
return rows[0];
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ❌ Bad: Vulnerable to NoSQL injection
|
|
123
|
-
async function vulnerableSearchMongo(userInput) {
|
|
124
|
-
const client = new MongoClient(mongoUrl);
|
|
125
|
-
await client.connect();
|
|
126
|
-
|
|
127
|
-
const db = client.db('myapp');
|
|
128
|
-
const users = db.collection('users');
|
|
129
|
-
|
|
130
|
-
// Dangerous: Direct use of user input
|
|
131
|
-
const result = await users.find(userInput).toArray();
|
|
132
|
-
|
|
133
|
-
return result;
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### 2. Cross-Site Scripting (XSS) | 跨站脚本攻击
|
|
138
|
-
|
|
139
|
-
```javascript
|
|
140
|
-
// ✅ Good: XSS Prevention
|
|
141
|
-
const DOMPurify = require('dompurify');
|
|
142
|
-
const { JSDOM } = require('jsdom');
|
|
143
|
-
|
|
144
|
-
const window = new JSDOM('').window;
|
|
145
|
-
const purify = DOMPurify(window);
|
|
146
|
-
|
|
147
|
-
// Input sanitization
|
|
148
|
-
function sanitizeHtml(dirty) {
|
|
149
|
-
return purify.sanitize(dirty, {
|
|
150
|
-
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],
|
|
151
|
-
ALLOWED_ATTR: []
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Output encoding for different contexts
|
|
156
|
-
function escapeHtml(unsafe) {
|
|
157
|
-
return unsafe
|
|
158
|
-
.replace(/&/g, "&")
|
|
159
|
-
.replace(/</g, "<")
|
|
160
|
-
.replace(/>/g, ">")
|
|
161
|
-
.replace(/"/g, """)
|
|
162
|
-
.replace(/'/g, "'");
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function escapeJavaScript(unsafe) {
|
|
166
|
-
return unsafe
|
|
167
|
-
.replace(/\\/g, "\\\\")
|
|
168
|
-
.replace(/'/g, "\\'")
|
|
169
|
-
.replace(/"/g, '\\"')
|
|
170
|
-
.replace(/\n/g, "\\n")
|
|
171
|
-
.replace(/\r/g, "\\r")
|
|
172
|
-
.replace(/\t/g, "\\t");
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// React component with proper escaping
|
|
176
|
-
import React from 'react';
|
|
177
|
-
|
|
178
|
-
function UserProfile({ user }) {
|
|
179
|
-
return (
|
|
180
|
-
<div>
|
|
181
|
-
{/* Safe: React automatically escapes */}
|
|
182
|
-
<h1>{user.name}</h1>
|
|
183
|
-
<p>{user.bio}</p>
|
|
184
|
-
|
|
185
|
-
{/* Safe: Sanitized HTML */}
|
|
186
|
-
<div dangerouslySetInnerHTML={{
|
|
187
|
-
__html: sanitizeHtml(user.description)
|
|
188
|
-
}} />
|
|
189
|
-
|
|
190
|
-
{/* Safe: URL validation */}
|
|
191
|
-
{isValidUrl(user.website) && (
|
|
192
|
-
<a href={user.website} target="_blank" rel="noopener noreferrer">
|
|
193
|
-
{user.website}
|
|
194
|
-
</a>
|
|
195
|
-
)}
|
|
196
|
-
</div>
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function isValidUrl(string) {
|
|
201
|
-
try {
|
|
202
|
-
const url = new URL(string);
|
|
203
|
-
return url.protocol === 'http:' || url.protocol === 'https:';
|
|
204
|
-
} catch (_) {
|
|
205
|
-
return false;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// ✅ Good: Content Security Policy
|
|
210
|
-
app.use((req, res, next) => {
|
|
211
|
-
res.setHeader(
|
|
212
|
-
'Content-Security-Policy',
|
|
213
|
-
"default-src 'self'; " +
|
|
214
|
-
"script-src 'self' 'unsafe-inline' https://trusted-cdn.com; " +
|
|
215
|
-
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; " +
|
|
216
|
-
"img-src 'self' data: https:; " +
|
|
217
|
-
"font-src 'self' https://fonts.gstatic.com; " +
|
|
218
|
-
"connect-src 'self' https://api.example.com; " +
|
|
219
|
-
"frame-ancestors 'none';"
|
|
220
|
-
);
|
|
221
|
-
next();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
// ❌ Bad: Vulnerable to XSS
|
|
225
|
-
function vulnerableRender(userInput) {
|
|
226
|
-
// Dangerous: Direct HTML insertion
|
|
227
|
-
document.getElementById('content').innerHTML = userInput;
|
|
228
|
-
|
|
229
|
-
// Dangerous: Unescaped output in template
|
|
230
|
-
return `<div>${userInput}</div>`;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
// ❌ Bad: Dangerous use of eval
|
|
234
|
-
function vulnerableExecute(userCode) {
|
|
235
|
-
// Extremely dangerous: Never use eval with user input
|
|
236
|
-
eval(userCode);
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### 3. Authentication and Session Management | 身份验证和会话管理
|
|
241
|
-
|
|
242
|
-
```javascript
|
|
243
|
-
// ✅ Good: Secure Authentication Implementation
|
|
244
|
-
const bcrypt = require('bcrypt');
|
|
245
|
-
const jwt = require('jsonwebtoken');
|
|
246
|
-
const crypto = require('crypto');
|
|
247
|
-
const rateLimit = require('express-rate-limit');
|
|
248
|
-
|
|
249
|
-
// Password hashing
|
|
250
|
-
async function hashPassword(password) {
|
|
251
|
-
const saltRounds = 12; // Adjust based on security requirements
|
|
252
|
-
return await bcrypt.hash(password, saltRounds);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
async function verifyPassword(password, hashedPassword) {
|
|
256
|
-
return await bcrypt.compare(password, hashedPassword);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Secure password requirements
|
|
260
|
-
function validatePassword(password) {
|
|
261
|
-
const minLength = 8;
|
|
262
|
-
const hasUpperCase = /[A-Z]/.test(password);
|
|
263
|
-
const hasLowerCase = /[a-z]/.test(password);
|
|
264
|
-
const hasNumbers = /\d/.test(password);
|
|
265
|
-
const hasSpecialChar = /[!@#$%^&*(),.?":{}|<>]/.test(password);
|
|
266
|
-
|
|
267
|
-
const errors = [];
|
|
268
|
-
|
|
269
|
-
if (password.length < minLength) {
|
|
270
|
-
errors.push(`Password must be at least ${minLength} characters long`);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (!hasUpperCase) {
|
|
274
|
-
errors.push('Password must contain at least one uppercase letter');
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (!hasLowerCase) {
|
|
278
|
-
errors.push('Password must contain at least one lowercase letter');
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (!hasNumbers) {
|
|
282
|
-
errors.push('Password must contain at least one number');
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (!hasSpecialChar) {
|
|
286
|
-
errors.push('Password must contain at least one special character');
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
isValid: errors.length === 0,
|
|
291
|
-
errors
|
|
292
|
-
};
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// JWT token management
|
|
296
|
-
const JWT_SECRET = process.env.JWT_SECRET || crypto.randomBytes(64).toString('hex');
|
|
297
|
-
const JWT_REFRESH_SECRET = process.env.JWT_REFRESH_SECRET || crypto.randomBytes(64).toString('hex');
|
|
298
|
-
|
|
299
|
-
function generateTokens(userId) {
|
|
300
|
-
const accessToken = jwt.sign(
|
|
301
|
-
{ userId, type: 'access' },
|
|
302
|
-
JWT_SECRET,
|
|
303
|
-
{ expiresIn: '15m' }
|
|
304
|
-
);
|
|
305
|
-
|
|
306
|
-
const refreshToken = jwt.sign(
|
|
307
|
-
{ userId, type: 'refresh' },
|
|
308
|
-
JWT_REFRESH_SECRET,
|
|
309
|
-
{ expiresIn: '7d' }
|
|
310
|
-
);
|
|
311
|
-
|
|
312
|
-
return { accessToken, refreshToken };
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
function verifyAccessToken(token) {
|
|
316
|
-
try {
|
|
317
|
-
const decoded = jwt.verify(token, JWT_SECRET);
|
|
318
|
-
if (decoded.type !== 'access') {
|
|
319
|
-
throw new Error('Invalid token type');
|
|
320
|
-
}
|
|
321
|
-
return decoded;
|
|
322
|
-
} catch (error) {
|
|
323
|
-
throw new Error('Invalid or expired token');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Rate limiting for authentication
|
|
328
|
-
const loginLimiter = rateLimit({
|
|
329
|
-
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
330
|
-
max: 5, // Limit each IP to 5 requests per windowMs
|
|
331
|
-
message: 'Too many login attempts, please try again later',
|
|
332
|
-
standardHeaders: true,
|
|
333
|
-
legacyHeaders: false,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// Secure login endpoint
|
|
337
|
-
app.post('/login', loginLimiter, async (req, res) => {
|
|
338
|
-
try {
|
|
339
|
-
const { email, password } = req.body;
|
|
340
|
-
|
|
341
|
-
// Input validation
|
|
342
|
-
if (!email || !password) {
|
|
343
|
-
return res.status(400).json({ error: 'Email and password are required' });
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// Find user
|
|
347
|
-
const user = await User.findOne({ email: email.toLowerCase() });
|
|
348
|
-
if (!user) {
|
|
349
|
-
// Don't reveal whether user exists
|
|
350
|
-
return res.status(401).json({ error: 'Invalid credentials' });
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
// Check if account is locked
|
|
354
|
-
if (user.lockUntil && user.lockUntil > Date.now()) {
|
|
355
|
-
return res.status(423).json({ error: 'Account temporarily locked' });
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Verify password
|
|
359
|
-
const isValidPassword = await verifyPassword(password, user.passwordHash);
|
|
360
|
-
|
|
361
|
-
if (!isValidPassword) {
|
|
362
|
-
// Increment failed attempts
|
|
363
|
-
await user.incFailedAttempts();
|
|
364
|
-
return res.status(401).json({ error: 'Invalid credentials' });
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Reset failed attempts on successful login
|
|
368
|
-
await user.resetFailedAttempts();
|
|
369
|
-
|
|
370
|
-
// Generate tokens
|
|
371
|
-
const { accessToken, refreshToken } = generateTokens(user._id);
|
|
372
|
-
|
|
373
|
-
// Store refresh token securely
|
|
374
|
-
await user.updateRefreshToken(refreshToken);
|
|
375
|
-
|
|
376
|
-
// Set secure cookie
|
|
377
|
-
res.cookie('refreshToken', refreshToken, {
|
|
378
|
-
httpOnly: true,
|
|
379
|
-
secure: process.env.NODE_ENV === 'production',
|
|
380
|
-
sameSite: 'strict',
|
|
381
|
-
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
|
|
382
|
-
});
|
|
383
|
-
|
|
384
|
-
res.json({
|
|
385
|
-
accessToken,
|
|
386
|
-
user: {
|
|
387
|
-
id: user._id,
|
|
388
|
-
email: user.email,
|
|
389
|
-
name: user.name
|
|
390
|
-
}
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
} catch (error) {
|
|
394
|
-
console.error('Login error:', error);
|
|
395
|
-
res.status(500).json({ error: 'Internal server error' });
|
|
396
|
-
}
|
|
397
|
-
});
|
|
398
|
-
|
|
399
|
-
// Multi-factor authentication
|
|
400
|
-
const speakeasy = require('speakeasy');
|
|
401
|
-
const QRCode = require('qrcode');
|
|
402
|
-
|
|
403
|
-
async function setupTwoFactor(userId) {
|
|
404
|
-
const secret = speakeasy.generateSecret({
|
|
405
|
-
name: `MyApp (${userId})`,
|
|
406
|
-
issuer: 'MyApp'
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
// Store secret temporarily (user must verify before enabling)
|
|
410
|
-
await User.findByIdAndUpdate(userId, {
|
|
411
|
-
tempTwoFactorSecret: secret.base32
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
// Generate QR code
|
|
415
|
-
const qrCodeUrl = await QRCode.toDataURL(secret.otpauth_url);
|
|
416
|
-
|
|
417
|
-
return {
|
|
418
|
-
secret: secret.base32,
|
|
419
|
-
qrCode: qrCodeUrl
|
|
420
|
-
};
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
function verifyTwoFactor(token, secret) {
|
|
424
|
-
return speakeasy.totp.verify({
|
|
425
|
-
secret,
|
|
426
|
-
encoding: 'base32',
|
|
427
|
-
token,
|
|
428
|
-
window: 2 // Allow some time drift
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// ❌ Bad: Insecure authentication
|
|
433
|
-
async function insecureLogin(email, password) {
|
|
434
|
-
// Bad: Plain text password storage
|
|
435
|
-
const user = await User.findOne({ email, password });
|
|
436
|
-
|
|
437
|
-
// Bad: Weak JWT secret
|
|
438
|
-
const token = jwt.sign({ userId: user.id }, 'secret123');
|
|
439
|
-
|
|
440
|
-
// Bad: No rate limiting, no input validation
|
|
441
|
-
return { token };
|
|
442
|
-
}
|
|
443
|
-
```
|
|
444
|
-
|
|
445
|
-
### 4. Access Control and Authorization | 访问控制和授权
|
|
446
|
-
|
|
447
|
-
```javascript
|
|
448
|
-
// ✅ Good: Role-Based Access Control (RBAC)
|
|
449
|
-
const permissions = {
|
|
450
|
-
'user:read': ['admin', 'manager', 'user'],
|
|
451
|
-
'user:write': ['admin', 'manager'],
|
|
452
|
-
'user:delete': ['admin'],
|
|
453
|
-
'report:read': ['admin', 'manager'],
|
|
454
|
-
'report:write': ['admin', 'manager'],
|
|
455
|
-
'system:admin': ['admin']
|
|
456
|
-
};
|
|
457
|
-
|
|
458
|
-
function hasPermission(userRole, permission) {
|
|
459
|
-
return permissions[permission]?.includes(userRole) || false;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// Middleware for permission checking
|
|
463
|
-
function requirePermission(permission) {
|
|
464
|
-
return (req, res, next) => {
|
|
465
|
-
const user = req.user; // Set by authentication middleware
|
|
466
|
-
|
|
467
|
-
if (!user) {
|
|
468
|
-
return res.status(401).json({ error: 'Authentication required' });
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
if (!hasPermission(user.role, permission)) {
|
|
472
|
-
return res.status(403).json({ error: 'Insufficient permissions' });
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
next();
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
// Resource-based authorization
|
|
480
|
-
async function canAccessResource(userId, resourceId, action) {
|
|
481
|
-
const resource = await Resource.findById(resourceId);
|
|
482
|
-
|
|
483
|
-
if (!resource) {
|
|
484
|
-
return false;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// Owner can do anything
|
|
488
|
-
if (resource.ownerId.toString() === userId.toString()) {
|
|
489
|
-
return true;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
// Check shared permissions
|
|
493
|
-
const permission = await Permission.findOne({
|
|
494
|
-
resourceId,
|
|
495
|
-
userId,
|
|
496
|
-
action: { $in: [action, 'all'] }
|
|
497
|
-
});
|
|
498
|
-
|
|
499
|
-
return !!permission;
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
// API endpoint with proper authorization
|
|
503
|
-
app.get('/api/users/:id',
|
|
504
|
-
authenticateToken,
|
|
505
|
-
requirePermission('user:read'),
|
|
506
|
-
async (req, res) => {
|
|
507
|
-
try {
|
|
508
|
-
const requestedUserId = req.params.id;
|
|
509
|
-
const currentUserId = req.user.id;
|
|
510
|
-
|
|
511
|
-
// Users can only access their own data unless they have admin role
|
|
512
|
-
if (requestedUserId !== currentUserId && req.user.role !== 'admin') {
|
|
513
|
-
return res.status(403).json({ error: 'Access denied' });
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const user = await User.findById(requestedUserId);
|
|
517
|
-
if (!user) {
|
|
518
|
-
return res.status(404).json({ error: 'User not found' });
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Filter sensitive data based on permissions
|
|
522
|
-
const userData = filterUserData(user, req.user.role);
|
|
523
|
-
|
|
524
|
-
res.json(userData);
|
|
525
|
-
} catch (error) {
|
|
526
|
-
console.error('Error fetching user:', error);
|
|
527
|
-
res.status(500).json({ error: 'Internal server error' });
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
);
|
|
531
|
-
|
|
532
|
-
function filterUserData(user, viewerRole) {
|
|
533
|
-
const baseData = {
|
|
534
|
-
id: user._id,
|
|
535
|
-
name: user.name,
|
|
536
|
-
email: user.email
|
|
537
|
-
};
|
|
538
|
-
|
|
539
|
-
// Admin can see everything
|
|
540
|
-
if (viewerRole === 'admin') {
|
|
541
|
-
return {
|
|
542
|
-
...baseData,
|
|
543
|
-
role: user.role,
|
|
544
|
-
createdAt: user.createdAt,
|
|
545
|
-
lastLogin: user.lastLogin,
|
|
546
|
-
isActive: user.isActive
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
// Regular users see limited data
|
|
551
|
-
return baseData;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
// ✅ Good: Attribute-Based Access Control (ABAC)
|
|
555
|
-
class AccessControlEngine {
|
|
556
|
-
constructor() {
|
|
557
|
-
this.policies = [];
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
addPolicy(policy) {
|
|
561
|
-
this.policies.push(policy);
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
async evaluate(subject, action, resource, context = {}) {
|
|
565
|
-
for (const policy of this.policies) {
|
|
566
|
-
const result = await policy.evaluate(subject, action, resource, context);
|
|
567
|
-
if (result === 'deny') {
|
|
568
|
-
return false;
|
|
569
|
-
}
|
|
570
|
-
if (result === 'allow') {
|
|
571
|
-
return true;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// Default deny
|
|
576
|
-
return false;
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
class Policy {
|
|
581
|
-
constructor(name, condition, effect) {
|
|
582
|
-
this.name = name;
|
|
583
|
-
this.condition = condition;
|
|
584
|
-
this.effect = effect; // 'allow' or 'deny'
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
async evaluate(subject, action, resource, context) {
|
|
588
|
-
if (await this.condition(subject, action, resource, context)) {
|
|
589
|
-
return this.effect;
|
|
590
|
-
}
|
|
591
|
-
return 'not_applicable';
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
// Example policies
|
|
596
|
-
const ownerPolicy = new Policy(
|
|
597
|
-
'owner-access',
|
|
598
|
-
async (subject, action, resource) => {
|
|
599
|
-
return resource.ownerId === subject.id;
|
|
600
|
-
},
|
|
601
|
-
'allow'
|
|
602
|
-
);
|
|
603
|
-
|
|
604
|
-
const businessHoursPolicy = new Policy(
|
|
605
|
-
'business-hours-only',
|
|
606
|
-
async (subject, action, resource, context) => {
|
|
607
|
-
const hour = new Date().getHours();
|
|
608
|
-
return hour >= 9 && hour <= 17; // 9 AM to 5 PM
|
|
609
|
-
},
|
|
610
|
-
'allow'
|
|
611
|
-
);
|
|
612
|
-
|
|
613
|
-
const acEngine = new AccessControlEngine();
|
|
614
|
-
acEngine.addPolicy(ownerPolicy);
|
|
615
|
-
acEngine.addPolicy(businessHoursPolicy);
|
|
616
|
-
```
|
|
617
|
-
|
|
618
|
-
## Input Validation and Sanitization | 输入验证和清理
|
|
619
|
-
|
|
620
|
-
### 1. Comprehensive Input Validation | 全面输入验证
|
|
621
|
-
|
|
622
|
-
```javascript
|
|
623
|
-
// ✅ Good: Input validation with Joi
|
|
624
|
-
const Joi = require('joi');
|
|
625
|
-
|
|
626
|
-
// User registration schema
|
|
627
|
-
const userRegistrationSchema = Joi.object({
|
|
628
|
-
name: Joi.string()
|
|
629
|
-
.min(2)
|
|
630
|
-
.max(50)
|
|
631
|
-
.pattern(/^[a-zA-Z\s]+$/)
|
|
632
|
-
.required()
|
|
633
|
-
.messages({
|
|
634
|
-
'string.pattern.base': 'Name can only contain letters and spaces'
|
|
635
|
-
}),
|
|
636
|
-
|
|
637
|
-
email: Joi.string()
|
|
638
|
-
.email({ minDomainSegments: 2 })
|
|
639
|
-
.required()
|
|
640
|
-
.lowercase(),
|
|
641
|
-
|
|
642
|
-
password: Joi.string()
|
|
643
|
-
.min(8)
|
|
644
|
-
.max(128)
|
|
645
|
-
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]/)
|
|
646
|
-
.required()
|
|
647
|
-
.messages({
|
|
648
|
-
'string.pattern.base': 'Password must contain at least one uppercase letter, one lowercase letter, one number, and one special character'
|
|
649
|
-
}),
|
|
650
|
-
|
|
651
|
-
age: Joi.number()
|
|
652
|
-
.integer()
|
|
653
|
-
.min(13)
|
|
654
|
-
.max(120)
|
|
655
|
-
.required(),
|
|
656
|
-
|
|
657
|
-
phone: Joi.string()
|
|
658
|
-
.pattern(/^\+?[\d\s\-\(\)]+$/)
|
|
659
|
-
.optional(),
|
|
660
|
-
|
|
661
|
-
website: Joi.string()
|
|
662
|
-
.uri({ scheme: ['http', 'https'] })
|
|
663
|
-
.optional()
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
// Validation middleware
|
|
667
|
-
function validateInput(schema) {
|
|
668
|
-
return (req, res, next) => {
|
|
669
|
-
const { error, value } = schema.validate(req.body, {
|
|
670
|
-
abortEarly: false,
|
|
671
|
-
stripUnknown: true
|
|
672
|
-
});
|
|
673
|
-
|
|
674
|
-
if (error) {
|
|
675
|
-
const errors = error.details.map(detail => ({
|
|
676
|
-
field: detail.path.join('.'),
|
|
677
|
-
message: detail.message
|
|
678
|
-
}));
|
|
679
|
-
|
|
680
|
-
return res.status(400).json({
|
|
681
|
-
error: 'Validation failed',
|
|
682
|
-
details: errors
|
|
683
|
-
});
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
req.validatedData = value;
|
|
687
|
-
next();
|
|
688
|
-
};
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// File upload validation
|
|
692
|
-
const multer = require('multer');
|
|
693
|
-
const path = require('path');
|
|
694
|
-
|
|
695
|
-
const fileFilter = (req, file, cb) => {
|
|
696
|
-
// Allowed file types
|
|
697
|
-
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'application/pdf'];
|
|
698
|
-
|
|
699
|
-
if (allowedTypes.includes(file.mimetype)) {
|
|
700
|
-
cb(null, true);
|
|
701
|
-
} else {
|
|
702
|
-
cb(new Error('Invalid file type. Only JPEG, PNG, GIF, and PDF files are allowed.'), false);
|
|
703
|
-
}
|
|
704
|
-
};
|
|
705
|
-
|
|
706
|
-
const upload = multer({
|
|
707
|
-
dest: 'uploads/',
|
|
708
|
-
limits: {
|
|
709
|
-
fileSize: 5 * 1024 * 1024, // 5MB limit
|
|
710
|
-
files: 5 // Maximum 5 files
|
|
711
|
-
},
|
|
712
|
-
fileFilter
|
|
713
|
-
});
|
|
714
|
-
|
|
715
|
-
// API endpoint with validation
|
|
716
|
-
app.post('/api/users',
|
|
717
|
-
validateInput(userRegistrationSchema),
|
|
718
|
-
async (req, res) => {
|
|
719
|
-
try {
|
|
720
|
-
const userData = req.validatedData;
|
|
721
|
-
|
|
722
|
-
// Additional business logic validation
|
|
723
|
-
const existingUser = await User.findOne({ email: userData.email });
|
|
724
|
-
if (existingUser) {
|
|
725
|
-
return res.status(409).json({ error: 'Email already registered' });
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// Hash password
|
|
729
|
-
userData.passwordHash = await hashPassword(userData.password);
|
|
730
|
-
delete userData.password;
|
|
731
|
-
|
|
732
|
-
const user = new User(userData);
|
|
733
|
-
await user.save();
|
|
734
|
-
|
|
735
|
-
res.status(201).json({
|
|
736
|
-
message: 'User created successfully',
|
|
737
|
-
user: {
|
|
738
|
-
id: user._id,
|
|
739
|
-
name: user.name,
|
|
740
|
-
email: user.email
|
|
741
|
-
}
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
} catch (error) {
|
|
745
|
-
console.error('User creation error:', error);
|
|
746
|
-
res.status(500).json({ error: 'Internal server error' });
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
);
|
|
750
|
-
|
|
751
|
-
// ✅ Good: SQL injection prevention with parameterized queries
|
|
752
|
-
async function searchProducts(filters) {
|
|
753
|
-
const { category, minPrice, maxPrice, searchTerm } = filters;
|
|
754
|
-
|
|
755
|
-
let query = 'SELECT * FROM products WHERE 1=1';
|
|
756
|
-
const params = [];
|
|
757
|
-
|
|
758
|
-
if (category) {
|
|
759
|
-
query += ' AND category = ?';
|
|
760
|
-
params.push(category);
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
if (minPrice !== undefined) {
|
|
764
|
-
query += ' AND price >= ?';
|
|
765
|
-
params.push(minPrice);
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
if (maxPrice !== undefined) {
|
|
769
|
-
query += ' AND price <= ?';
|
|
770
|
-
params.push(maxPrice);
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
if (searchTerm) {
|
|
774
|
-
query += ' AND (name LIKE ? OR description LIKE ?)';
|
|
775
|
-
params.push(`%${searchTerm}%`, `%${searchTerm}%`);
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
const [rows] = await connection.execute(query, params);
|
|
779
|
-
return rows;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
// ❌ Bad: No input validation
|
|
783
|
-
app.post('/api/users', async (req, res) => {
|
|
784
|
-
// Dangerous: No validation of input data
|
|
785
|
-
const user = new User(req.body);
|
|
786
|
-
await user.save();
|
|
787
|
-
res.json(user);
|
|
788
|
-
});
|
|
789
|
-
```
|
|
790
|
-
|
|
791
|
-
## Cryptography and Data Protection | 密码学和数据保护
|
|
792
|
-
|
|
793
|
-
### 1. Encryption and Hashing | 加密和哈希
|
|
794
|
-
|
|
795
|
-
```javascript
|
|
796
|
-
// ✅ Good: Proper encryption implementation
|
|
797
|
-
const crypto = require('crypto');
|
|
798
|
-
|
|
799
|
-
class EncryptionService {
|
|
800
|
-
constructor() {
|
|
801
|
-
this.algorithm = 'aes-256-gcm';
|
|
802
|
-
this.keyLength = 32; // 256 bits
|
|
803
|
-
this.ivLength = 16; // 128 bits
|
|
804
|
-
this.tagLength = 16; // 128 bits
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
// Generate a random encryption key
|
|
808
|
-
generateKey() {
|
|
809
|
-
return crypto.randomBytes(this.keyLength);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
// Encrypt data
|
|
813
|
-
encrypt(plaintext, key) {
|
|
814
|
-
const iv = crypto.randomBytes(this.ivLength);
|
|
815
|
-
const cipher = crypto.createCipher(this.algorithm, key, iv);
|
|
816
|
-
|
|
817
|
-
let encrypted = cipher.update(plaintext, 'utf8', 'hex');
|
|
818
|
-
encrypted += cipher.final('hex');
|
|
819
|
-
|
|
820
|
-
const tag = cipher.getAuthTag();
|
|
821
|
-
|
|
822
|
-
// Return IV + tag + encrypted data
|
|
823
|
-
return {
|
|
824
|
-
iv: iv.toString('hex'),
|
|
825
|
-
tag: tag.toString('hex'),
|
|
826
|
-
encrypted: encrypted
|
|
827
|
-
};
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Decrypt data
|
|
831
|
-
decrypt(encryptedData, key) {
|
|
832
|
-
const { iv, tag, encrypted } = encryptedData;
|
|
833
|
-
|
|
834
|
-
const decipher = crypto.createDecipher(
|
|
835
|
-
this.algorithm,
|
|
836
|
-
key,
|
|
837
|
-
Buffer.from(iv, 'hex')
|
|
838
|
-
);
|
|
839
|
-
|
|
840
|
-
decipher.setAuthTag(Buffer.from(tag, 'hex'));
|
|
841
|
-
|
|
842
|
-
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
843
|
-
decrypted += decipher.final('utf8');
|
|
844
|
-
|
|
845
|
-
return decrypted;
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
// Hash data with salt
|
|
849
|
-
hashWithSalt(data, salt = null) {
|
|
850
|
-
if (!salt) {
|
|
851
|
-
salt = crypto.randomBytes(32);
|
|
852
|
-
}
|
|
853
|
-
|
|
854
|
-
const hash = crypto.pbkdf2Sync(data, salt, 100000, 64, 'sha512');
|
|
855
|
-
|
|
856
|
-
return {
|
|
857
|
-
hash: hash.toString('hex'),
|
|
858
|
-
salt: salt.toString('hex')
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
// Verify hash
|
|
863
|
-
verifyHash(data, hash, salt) {
|
|
864
|
-
const { hash: computedHash } = this.hashWithSalt(
|
|
865
|
-
data,
|
|
866
|
-
Buffer.from(salt, 'hex')
|
|
867
|
-
);
|
|
868
|
-
|
|
869
|
-
return crypto.timingSafeEqual(
|
|
870
|
-
Buffer.from(hash, 'hex'),
|
|
871
|
-
Buffer.from(computedHash, 'hex')
|
|
872
|
-
);
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
// ✅ Good: Secure random token generation
|
|
877
|
-
function generateSecureToken(length = 32) {
|
|
878
|
-
return crypto.randomBytes(length).toString('hex');
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
function generateApiKey() {
|
|
882
|
-
const prefix = 'ak_';
|
|
883
|
-
const randomPart = crypto.randomBytes(24).toString('base64url');
|
|
884
|
-
return prefix + randomPart;
|
|
885
|
-
}
|
|
886
|
-
|
|
887
|
-
// ✅ Good: Digital signatures
|
|
888
|
-
class SignatureService {
|
|
889
|
-
constructor() {
|
|
890
|
-
this.algorithm = 'sha256';
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
// Generate key pair
|
|
894
|
-
generateKeyPair() {
|
|
895
|
-
return crypto.generateKeyPairSync('rsa', {
|
|
896
|
-
modulusLength: 2048,
|
|
897
|
-
publicKeyEncoding: {
|
|
898
|
-
type: 'spki',
|
|
899
|
-
format: 'pem'
|
|
900
|
-
},
|
|
901
|
-
privateKeyEncoding: {
|
|
902
|
-
type: 'pkcs8',
|
|
903
|
-
format: 'pem'
|
|
904
|
-
}
|
|
905
|
-
});
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
// Sign data
|
|
909
|
-
sign(data, privateKey) {
|
|
910
|
-
const sign = crypto.createSign(this.algorithm);
|
|
911
|
-
sign.update(data);
|
|
912
|
-
return sign.sign(privateKey, 'hex');
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
// Verify signature
|
|
916
|
-
verify(data, signature, publicKey) {
|
|
917
|
-
const verify = crypto.createVerify(this.algorithm);
|
|
918
|
-
verify.update(data);
|
|
919
|
-
return verify.verify(publicKey, signature, 'hex');
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
|
|
923
|
-
// ✅ Good: Secure session management
|
|
924
|
-
const session = require('express-session');
|
|
925
|
-
const MongoStore = require('connect-mongo');
|
|
926
|
-
|
|
927
|
-
app.use(session({
|
|
928
|
-
secret: process.env.SESSION_SECRET || crypto.randomBytes(64).toString('hex'),
|
|
929
|
-
name: 'sessionId', // Don't use default name
|
|
930
|
-
resave: false,
|
|
931
|
-
saveUninitialized: false,
|
|
932
|
-
store: MongoStore.create({
|
|
933
|
-
mongoUrl: process.env.MONGODB_URI,
|
|
934
|
-
touchAfter: 24 * 3600 // Lazy session update
|
|
935
|
-
}),
|
|
936
|
-
cookie: {
|
|
937
|
-
secure: process.env.NODE_ENV === 'production', // HTTPS only in production
|
|
938
|
-
httpOnly: true, // Prevent XSS
|
|
939
|
-
maxAge: 1000 * 60 * 60 * 24, // 24 hours
|
|
940
|
-
sameSite: 'strict' // CSRF protection
|
|
941
|
-
}
|
|
942
|
-
}));
|
|
943
|
-
|
|
944
|
-
// ❌ Bad: Weak encryption
|
|
945
|
-
function weakEncryption(data) {
|
|
946
|
-
// Bad: Using deprecated algorithm
|
|
947
|
-
const cipher = crypto.createCipher('des', 'weak-key');
|
|
948
|
-
return cipher.update(data, 'utf8', 'hex') + cipher.final('hex');
|
|
949
|
-
}
|
|
950
|
-
|
|
951
|
-
// ❌ Bad: Predictable tokens
|
|
952
|
-
function weakToken() {
|
|
953
|
-
// Bad: Predictable timestamp-based token
|
|
954
|
-
return Date.now().toString() + Math.random().toString();
|
|
955
|
-
}
|
|
956
|
-
```
|
|
957
|
-
|
|
958
|
-
### 2. Secure Communication | 安全通信
|
|
959
|
-
|
|
960
|
-
```javascript
|
|
961
|
-
// ✅ Good: HTTPS configuration
|
|
962
|
-
const https = require('https');
|
|
963
|
-
const fs = require('fs');
|
|
964
|
-
|
|
965
|
-
// SSL/TLS configuration
|
|
966
|
-
const httpsOptions = {
|
|
967
|
-
key: fs.readFileSync('path/to/private-key.pem'),
|
|
968
|
-
cert: fs.readFileSync('path/to/certificate.pem'),
|
|
969
|
-
// Additional security options
|
|
970
|
-
secureProtocol: 'TLSv1_2_method',
|
|
971
|
-
ciphers: [
|
|
972
|
-
'ECDHE-RSA-AES128-GCM-SHA256',
|
|
973
|
-
'ECDHE-RSA-AES256-GCM-SHA384',
|
|
974
|
-
'ECDHE-RSA-AES128-SHA256',
|
|
975
|
-
'ECDHE-RSA-AES256-SHA384'
|
|
976
|
-
].join(':'),
|
|
977
|
-
honorCipherOrder: true
|
|
978
|
-
};
|
|
979
|
-
|
|
980
|
-
const server = https.createServer(httpsOptions, app);
|
|
981
|
-
|
|
982
|
-
// ✅ Good: Security headers middleware
|
|
983
|
-
const helmet = require('helmet');
|
|
984
|
-
|
|
985
|
-
app.use(helmet({
|
|
986
|
-
contentSecurityPolicy: {
|
|
987
|
-
directives: {
|
|
988
|
-
defaultSrc: ["'self'"],
|
|
989
|
-
styleSrc: ["'self'", "'unsafe-inline'", "https://fonts.googleapis.com"],
|
|
990
|
-
fontSrc: ["'self'", "https://fonts.gstatic.com"],
|
|
991
|
-
imgSrc: ["'self'", "data:", "https:"],
|
|
992
|
-
scriptSrc: ["'self'"],
|
|
993
|
-
connectSrc: ["'self'", "https://api.example.com"]
|
|
994
|
-
}
|
|
995
|
-
},
|
|
996
|
-
hsts: {
|
|
997
|
-
maxAge: 31536000,
|
|
998
|
-
includeSubDomains: true,
|
|
999
|
-
preload: true
|
|
1000
|
-
}
|
|
1001
|
-
}));
|
|
1002
|
-
|
|
1003
|
-
// ✅ Good: API rate limiting
|
|
1004
|
-
const rateLimit = require('express-rate-limit');
|
|
1005
|
-
|
|
1006
|
-
const apiLimiter = rateLimit({
|
|
1007
|
-
windowMs: 15 * 60 * 1000, // 15 minutes
|
|
1008
|
-
max: 100, // Limit each IP to 100 requests per windowMs
|
|
1009
|
-
message: 'Too many requests from this IP, please try again later.',
|
|
1010
|
-
standardHeaders: true,
|
|
1011
|
-
legacyHeaders: false,
|
|
1012
|
-
});
|
|
1013
|
-
|
|
1014
|
-
const strictLimiter = rateLimit({
|
|
1015
|
-
windowMs: 15 * 60 * 1000,
|
|
1016
|
-
max: 5, // Stricter limit for sensitive endpoints
|
|
1017
|
-
skipSuccessfulRequests: true
|
|
1018
|
-
});
|
|
1019
|
-
|
|
1020
|
-
app.use('/api/', apiLimiter);
|
|
1021
|
-
app.use('/api/auth/', strictLimiter);
|
|
1022
|
-
|
|
1023
|
-
// ✅ Good: Request validation and sanitization
|
|
1024
|
-
const validator = require('validator');
|
|
1025
|
-
|
|
1026
|
-
function sanitizeInput(req, res, next) {
|
|
1027
|
-
// Sanitize string inputs
|
|
1028
|
-
for (const key in req.body) {
|
|
1029
|
-
if (typeof req.body[key] === 'string') {
|
|
1030
|
-
req.body[key] = validator.escape(req.body[key]);
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// Validate and sanitize specific fields
|
|
1035
|
-
if (req.body.email) {
|
|
1036
|
-
req.body.email = validator.normalizeEmail(req.body.email);
|
|
1037
|
-
if (!validator.isEmail(req.body.email)) {
|
|
1038
|
-
return res.status(400).json({ error: 'Invalid email format' });
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
|
|
1042
|
-
if (req.body.url) {
|
|
1043
|
-
if (!validator.isURL(req.body.url, { protocols: ['http', 'https'] })) {
|
|
1044
|
-
return res.status(400).json({ error: 'Invalid URL format' });
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
next();
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
app.use(sanitizeInput);
|
|
1052
|
-
```
|
|
1053
|
-
|
|
1054
|
-
## Security Testing and Monitoring | 安全测试和监控
|
|
1055
|
-
|
|
1056
|
-
### 1. Security Testing | 安全测试
|
|
1057
|
-
|
|
1058
|
-
```javascript
|
|
1059
|
-
// ✅ Good: Security-focused unit tests
|
|
1060
|
-
describe('Authentication Security', () => {
|
|
1061
|
-
describe('Password validation', () => {
|
|
1062
|
-
it('should reject weak passwords', () => {
|
|
1063
|
-
const weakPasswords = [
|
|
1064
|
-
'password',
|
|
1065
|
-
'123456',
|
|
1066
|
-
'qwerty',
|
|
1067
|
-
'abc123',
|
|
1068
|
-
'password123'
|
|
1069
|
-
];
|
|
1070
|
-
|
|
1071
|
-
weakPasswords.forEach(password => {
|
|
1072
|
-
const result = validatePassword(password);
|
|
1073
|
-
expect(result.isValid).toBe(false);
|
|
1074
|
-
});
|
|
1075
|
-
});
|
|
1076
|
-
|
|
1077
|
-
it('should accept strong passwords', () => {
|
|
1078
|
-
const strongPasswords = [
|
|
1079
|
-
'MyStr0ng!Pass',
|
|
1080
|
-
'C0mplex@Password123',
|
|
1081
|
-
'Secure#Pass2023!'
|
|
1082
|
-
];
|
|
1083
|
-
|
|
1084
|
-
strongPasswords.forEach(password => {
|
|
1085
|
-
const result = validatePassword(password);
|
|
1086
|
-
expect(result.isValid).toBe(true);
|
|
1087
|
-
});
|
|
1088
|
-
});
|
|
1089
|
-
});
|
|
1090
|
-
|
|
1091
|
-
describe('SQL injection prevention', () => {
|
|
1092
|
-
it('should handle malicious input safely', async () => {
|
|
1093
|
-
const maliciousInputs = [
|
|
1094
|
-
"'; DROP TABLE users; --",
|
|
1095
|
-
"1' OR '1'='1",
|
|
1096
|
-
"admin'/*",
|
|
1097
|
-
"1; DELETE FROM users WHERE 1=1; --"
|
|
1098
|
-
];
|
|
1099
|
-
|
|
1100
|
-
for (const input of maliciousInputs) {
|
|
1101
|
-
const result = await getUserById(input);
|
|
1102
|
-
expect(result).toBeNull(); // Should not return any data
|
|
1103
|
-
}
|
|
1104
|
-
});
|
|
1105
|
-
});
|
|
1106
|
-
|
|
1107
|
-
describe('XSS prevention', () => {
|
|
1108
|
-
it('should sanitize HTML input', () => {
|
|
1109
|
-
const maliciousInputs = [
|
|
1110
|
-
'<script>alert("XSS")</script>',
|
|
1111
|
-
'<img src="x" onerror="alert(1)">',
|
|
1112
|
-
'javascript:alert("XSS")',
|
|
1113
|
-
'<svg onload="alert(1)">'
|
|
1114
|
-
];
|
|
1115
|
-
|
|
1116
|
-
maliciousInputs.forEach(input => {
|
|
1117
|
-
const sanitized = sanitizeHtml(input);
|
|
1118
|
-
expect(sanitized).not.toContain('<script>');
|
|
1119
|
-
expect(sanitized).not.toContain('javascript:');
|
|
1120
|
-
expect(sanitized).not.toContain('onerror');
|
|
1121
|
-
expect(sanitized).not.toContain('onload');
|
|
1122
|
-
});
|
|
1123
|
-
});
|
|
1124
|
-
});
|
|
1125
|
-
});
|
|
1126
|
-
|
|
1127
|
-
// ✅ Good: Penetration testing helpers
|
|
1128
|
-
class SecurityTester {
|
|
1129
|
-
constructor(baseUrl) {
|
|
1130
|
-
this.baseUrl = baseUrl;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
async testSqlInjection(endpoint, params) {
|
|
1134
|
-
const sqlPayloads = [
|
|
1135
|
-
"' OR '1'='1",
|
|
1136
|
-
"'; DROP TABLE users; --",
|
|
1137
|
-
"1' UNION SELECT * FROM users --",
|
|
1138
|
-
"admin'/*"
|
|
1139
|
-
];
|
|
1140
|
-
|
|
1141
|
-
const results = [];
|
|
1142
|
-
|
|
1143
|
-
for (const payload of sqlPayloads) {
|
|
1144
|
-
try {
|
|
1145
|
-
const testParams = { ...params };
|
|
1146
|
-
// Inject payload into each parameter
|
|
1147
|
-
for (const key in testParams) {
|
|
1148
|
-
testParams[key] = payload;
|
|
1149
|
-
|
|
1150
|
-
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
1151
|
-
method: 'POST',
|
|
1152
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1153
|
-
body: JSON.stringify(testParams)
|
|
1154
|
-
});
|
|
1155
|
-
|
|
1156
|
-
results.push({
|
|
1157
|
-
payload,
|
|
1158
|
-
parameter: key,
|
|
1159
|
-
status: response.status,
|
|
1160
|
-
vulnerable: response.status === 200 && response.headers.get('content-length') > 1000
|
|
1161
|
-
});
|
|
1162
|
-
}
|
|
1163
|
-
} catch (error) {
|
|
1164
|
-
results.push({
|
|
1165
|
-
payload,
|
|
1166
|
-
error: error.message
|
|
1167
|
-
});
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
return results;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
async testXss(endpoint, params) {
|
|
1175
|
-
const xssPayloads = [
|
|
1176
|
-
'<script>alert("XSS")</script>',
|
|
1177
|
-
'<img src="x" onerror="alert(1)">',
|
|
1178
|
-
'javascript:alert("XSS")',
|
|
1179
|
-
'<svg onload="alert(1)">'
|
|
1180
|
-
];
|
|
1181
|
-
|
|
1182
|
-
const results = [];
|
|
1183
|
-
|
|
1184
|
-
for (const payload of xssPayloads) {
|
|
1185
|
-
const testParams = { ...params };
|
|
1186
|
-
|
|
1187
|
-
for (const key in testParams) {
|
|
1188
|
-
testParams[key] = payload;
|
|
1189
|
-
|
|
1190
|
-
const response = await fetch(`${this.baseUrl}${endpoint}`, {
|
|
1191
|
-
method: 'POST',
|
|
1192
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1193
|
-
body: JSON.stringify(testParams)
|
|
1194
|
-
});
|
|
1195
|
-
|
|
1196
|
-
const responseText = await response.text();
|
|
1197
|
-
|
|
1198
|
-
results.push({
|
|
1199
|
-
payload,
|
|
1200
|
-
parameter: key,
|
|
1201
|
-
vulnerable: responseText.includes(payload) && !responseText.includes('<script>')
|
|
1202
|
-
});
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
return results;
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
```
|
|
1210
|
-
|
|
1211
|
-
### 2. Security Monitoring | 安全监控
|
|
1212
|
-
|
|
1213
|
-
```javascript
|
|
1214
|
-
// ✅ Good: Security event logging
|
|
1215
|
-
const winston = require('winston');
|
|
1216
|
-
|
|
1217
|
-
const securityLogger = winston.createLogger({
|
|
1218
|
-
level: 'info',
|
|
1219
|
-
format: winston.format.combine(
|
|
1220
|
-
winston.format.timestamp(),
|
|
1221
|
-
winston.format.errors({ stack: true }),
|
|
1222
|
-
winston.format.json()
|
|
1223
|
-
),
|
|
1224
|
-
transports: [
|
|
1225
|
-
new winston.transports.File({ filename: 'logs/security.log' }),
|
|
1226
|
-
new winston.transports.Console()
|
|
1227
|
-
]
|
|
1228
|
-
});
|
|
1229
|
-
|
|
1230
|
-
// Security event types
|
|
1231
|
-
const SecurityEvents = {
|
|
1232
|
-
LOGIN_SUCCESS: 'login_success',
|
|
1233
|
-
LOGIN_FAILURE: 'login_failure',
|
|
1234
|
-
LOGIN_BLOCKED: 'login_blocked',
|
|
1235
|
-
PASSWORD_CHANGE: 'password_change',
|
|
1236
|
-
PERMISSION_DENIED: 'permission_denied',
|
|
1237
|
-
SUSPICIOUS_ACTIVITY: 'suspicious_activity',
|
|
1238
|
-
DATA_ACCESS: 'data_access',
|
|
1239
|
-
ADMIN_ACTION: 'admin_action'
|
|
1240
|
-
};
|
|
1241
|
-
|
|
1242
|
-
function logSecurityEvent(eventType, details) {
|
|
1243
|
-
securityLogger.info({
|
|
1244
|
-
event: eventType,
|
|
1245
|
-
timestamp: new Date().toISOString(),
|
|
1246
|
-
...details
|
|
1247
|
-
});
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
// Middleware for security logging
|
|
1251
|
-
function securityLoggingMiddleware(req, res, next) {
|
|
1252
|
-
const originalSend = res.send;
|
|
1253
|
-
|
|
1254
|
-
res.send = function(data) {
|
|
1255
|
-
// Log failed authentication attempts
|
|
1256
|
-
if (res.statusCode === 401) {
|
|
1257
|
-
logSecurityEvent(SecurityEvents.LOGIN_FAILURE, {
|
|
1258
|
-
ip: req.ip,
|
|
1259
|
-
userAgent: req.get('User-Agent'),
|
|
1260
|
-
endpoint: req.path,
|
|
1261
|
-
method: req.method
|
|
1262
|
-
});
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
// Log permission denied
|
|
1266
|
-
if (res.statusCode === 403) {
|
|
1267
|
-
logSecurityEvent(SecurityEvents.PERMISSION_DENIED, {
|
|
1268
|
-
ip: req.ip,
|
|
1269
|
-
userId: req.user?.id,
|
|
1270
|
-
endpoint: req.path,
|
|
1271
|
-
method: req.method
|
|
1272
|
-
});
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
originalSend.call(this, data);
|
|
1276
|
-
};
|
|
1277
|
-
|
|
1278
|
-
next();
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
// ✅ Good: Intrusion detection
|
|
1282
|
-
class IntrusionDetector {
|
|
1283
|
-
constructor() {
|
|
1284
|
-
this.suspiciousPatterns = [
|
|
1285
|
-
/(\bor\b|\band\b).*=.*=/i, // SQL injection patterns
|
|
1286
|
-
/<script[^>]*>.*?<\/script>/i, // XSS patterns
|
|
1287
|
-
/javascript:/i,
|
|
1288
|
-
/vbscript:/i,
|
|
1289
|
-
/onload|onerror|onclick/i,
|
|
1290
|
-
/\.\.\//g, // Path traversal
|
|
1291
|
-
/\/etc\/passwd/i,
|
|
1292
|
-
/cmd\.exe|powershell/i
|
|
1293
|
-
];
|
|
1294
|
-
|
|
1295
|
-
this.rateLimits = new Map();
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
analyzeRequest(req) {
|
|
1299
|
-
const threats = [];
|
|
1300
|
-
|
|
1301
|
-
// Check for suspicious patterns in all input
|
|
1302
|
-
const inputs = [
|
|
1303
|
-
...Object.values(req.query || {}),
|
|
1304
|
-
...Object.values(req.body || {}),
|
|
1305
|
-
req.get('User-Agent') || '',
|
|
1306
|
-
req.get('Referer') || ''
|
|
1307
|
-
];
|
|
1308
|
-
|
|
1309
|
-
for (const input of inputs) {
|
|
1310
|
-
if (typeof input === 'string') {
|
|
1311
|
-
for (const pattern of this.suspiciousPatterns) {
|
|
1312
|
-
if (pattern.test(input)) {
|
|
1313
|
-
threats.push({
|
|
1314
|
-
type: 'suspicious_pattern',
|
|
1315
|
-
pattern: pattern.toString(),
|
|
1316
|
-
input: input.substring(0, 100) // Truncate for logging
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
// Rate limiting check
|
|
1324
|
-
const clientId = req.ip;
|
|
1325
|
-
const now = Date.now();
|
|
1326
|
-
const windowMs = 60000; // 1 minute
|
|
1327
|
-
const maxRequests = 100;
|
|
1328
|
-
|
|
1329
|
-
if (!this.rateLimits.has(clientId)) {
|
|
1330
|
-
this.rateLimits.set(clientId, []);
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
const requests = this.rateLimits.get(clientId);
|
|
1334
|
-
const recentRequests = requests.filter(time => now - time < windowMs);
|
|
1335
|
-
|
|
1336
|
-
if (recentRequests.length >= maxRequests) {
|
|
1337
|
-
threats.push({
|
|
1338
|
-
type: 'rate_limit_exceeded',
|
|
1339
|
-
requestCount: recentRequests.length,
|
|
1340
|
-
windowMs
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
recentRequests.push(now);
|
|
1345
|
-
this.rateLimits.set(clientId, recentRequests);
|
|
1346
|
-
|
|
1347
|
-
return threats;
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
const intrusionDetector = new IntrusionDetector();
|
|
1352
|
-
|
|
1353
|
-
app.use((req, res, next) => {
|
|
1354
|
-
const threats = intrusionDetector.analyzeRequest(req);
|
|
1355
|
-
|
|
1356
|
-
if (threats.length > 0) {
|
|
1357
|
-
logSecurityEvent(SecurityEvents.SUSPICIOUS_ACTIVITY, {
|
|
1358
|
-
ip: req.ip,
|
|
1359
|
-
userAgent: req.get('User-Agent'),
|
|
1360
|
-
endpoint: req.path,
|
|
1361
|
-
method: req.method,
|
|
1362
|
-
threats
|
|
1363
|
-
});
|
|
1364
|
-
|
|
1365
|
-
// Block request if high-risk threats detected
|
|
1366
|
-
const highRiskThreats = threats.filter(t =>
|
|
1367
|
-
t.type === 'suspicious_pattern' || t.type === 'rate_limit_exceeded'
|
|
1368
|
-
);
|
|
1369
|
-
|
|
1370
|
-
if (highRiskThreats.length > 0) {
|
|
1371
|
-
return res.status(429).json({ error: 'Request blocked due to suspicious activity' });
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
next();
|
|
1376
|
-
});
|
|
1377
|
-
```
|
|
1378
|
-
|
|
1379
|
-
## Security Checklist | 安全检查清单
|
|
1380
|
-
|
|
1381
|
-
- [ ] Input validation is implemented for all user inputs
|
|
1382
|
-
- [ ] SQL injection prevention with parameterized queries
|
|
1383
|
-
- [ ] XSS prevention with proper output encoding
|
|
1384
|
-
- [ ] Authentication uses strong password requirements
|
|
1385
|
-
- [ ] Multi-factor authentication is available for sensitive accounts
|
|
1386
|
-
- [ ] Authorization checks are implemented at all levels
|
|
1387
|
-
- [ ] Sensitive data is encrypted at rest and in transit
|
|
1388
|
-
- [ ] Security headers are properly configured
|
|
1389
|
-
- [ ] Rate limiting is implemented for API endpoints
|
|
1390
|
-
- [ ] Security logging and monitoring are in place
|
|
1391
|
-
- [ ] Regular security testing and code reviews
|
|
1392
|
-
- [ ] Dependencies are regularly updated and scanned for vulnerabilities
|
|
1393
|
-
- [ ] Error messages don't reveal sensitive information
|
|
1394
|
-
- [ ] Session management is secure
|
|
1395
|
-
- [ ] File uploads are properly validated and sandboxed
|
|
1396
|
-
|
|
1397
|
-
## 安全检查清单
|
|
1398
|
-
|
|
1399
|
-
- [ ] 对所有用户输入实施输入验证
|
|
1400
|
-
- [ ] 使用参数化查询防止 SQL 注入
|
|
1401
|
-
- [ ] 通过适当的输出编码防止 XSS
|
|
1402
|
-
- [ ] 身份验证使用强密码要求
|
|
1403
|
-
- [ ] 敏感账户可使用多因素身份验证
|
|
1404
|
-
- [ ] 在所有级别实施授权检查
|
|
1405
|
-
- [ ] 敏感数据在静态和传输中加密
|
|
1406
|
-
- [ ] 正确配置安全标头
|
|
1407
|
-
- [ ] 为 API 端点实施速率限制
|
|
1408
|
-
- [ ] 建立安全日志记录和监控
|
|
1409
|
-
- [ ] 定期进行安全测试和代码审查
|
|
1410
|
-
- [ ] 定期更新依赖项并扫描漏洞
|
|
1411
|
-
- [ ] 错误消息不泄露敏感信息
|
|
1412
|
-
- [ ] 会话管理安全
|
|
1413
|
-
- [ ] 文件上传经过适当验证和沙箱化
|