Run prettier

pull/3734/head
Kamran Ahmed 2 years ago
parent d081ecf5b3
commit 7434ff71eb
  1. 7
      .prettierignore
  2. 2
      astro.config.mjs
  3. 33
      bin/best-practice-dirs.cjs
  4. 3
      bin/readme.md
  5. 9
      bin/roadmap-content.cjs
  6. 5
      bin/roadmap-dirs.cjs
  7. 27
      bin/update-sponsors.cjs
  8. 20
      code_of_conduct.md
  9. 1
      package.json
  10. 2
      playwright.config.ts
  11. 4748
      pnpm-lock.yaml
  12. 14
      sitemap.mjs
  13. 77
      src/components/TopicOverlay/topic.js
  14. 47
      src/data/best-practices/api-security/api-security.md
  15. 2
      src/data/best-practices/api-security/content/api-gateway.md
  16. 2
      src/data/best-practices/api-security/content/authentication-mechanisms.md
  17. 2
      src/data/best-practices/api-security/content/authorization-header.md
  18. 2
      src/data/best-practices/api-security/content/avoid-http-blocking.md
  19. 2
      src/data/best-practices/api-security/content/avoid-logging-sensitive-data.md
  20. 2
      src/data/best-practices/api-security/content/avoid-personal-id-urls.md
  21. 2
      src/data/best-practices/api-security/content/avoid-sensitive-data.md
  22. 2
      src/data/best-practices/api-security/content/cdn-for-file-uploads.md
  23. 2
      src/data/best-practices/api-security/content/centralized-logins.md
  24. 2
      src/data/best-practices/api-security/content/check-dependencies.md
  25. 2
      src/data/best-practices/api-security/content/code-review-process.md
  26. 2
      src/data/best-practices/api-security/content/csp-header.md
  27. 2
      src/data/best-practices/api-security/content/debug-mode-off.md
  28. 2
      src/data/best-practices/api-security/content/directory-listings.md
  29. 2
      src/data/best-practices/api-security/content/disable-entity-expansion.md
  30. 2
      src/data/best-practices/api-security/content/disable-entity-parsing-xml.md
  31. 4
      src/data/best-practices/api-security/content/endpoint-authentication.md
  32. 2
      src/data/best-practices/api-security/content/force-content-type.md
  33. 2
      src/data/best-practices/api-security/content/good-jwt-secret.md
  34. 2
      src/data/best-practices/api-security/content/hsts-header.md
  35. 2
      src/data/best-practices/api-security/content/index.md
  36. 2
      src/data/best-practices/api-security/content/jwt-algorithm.md
  37. 2
      src/data/best-practices/api-security/content/jwt-payload.md
  38. 2
      src/data/best-practices/api-security/content/monitor-everything.md
  39. 2
      src/data/best-practices/api-security/content/no-sniff-header.md
  40. 2
      src/data/best-practices/api-security/content/non-executable-stacks.md
  41. 2
      src/data/best-practices/api-security/content/oauth-redirect-ui.md
  42. 2
      src/data/best-practices/api-security/content/only-server-side-encryption.md
  43. 2
      src/data/best-practices/api-security/content/prefer-uuid.md
  44. 2
      src/data/best-practices/api-security/content/proper-http-methods.md
  45. 3
      src/data/best-practices/api-security/content/proper-response-code.md
  46. 2
      src/data/best-practices/api-security/content/recommended-resources.md
  47. 2
      src/data/best-practices/api-security/content/remove-fingerprint-header.md
  48. 1
      src/data/best-practices/api-security/content/restrict-private-apis.md
  49. 2
      src/data/best-practices/api-security/content/rollback-deployments.md
  50. 2
      src/data/best-practices/api-security/content/run-security-analysis.md
  51. 2
      src/data/best-practices/api-security/content/sensitive-data-encryption.md
  52. 2
      src/data/best-practices/api-security/content/set-alerts.md
  53. 4
      src/data/best-practices/api-security/content/throttle-requests.md
  54. 2
      src/data/best-practices/api-security/content/token-expiry.md
  55. 2
      src/data/best-practices/api-security/content/unit-integration-tests.md
  56. 1
      src/data/best-practices/api-security/content/use-https.md
  57. 2
      src/data/best-practices/api-security/content/use-ids-ips-system.md
  58. 2
      src/data/best-practices/api-security/content/use-standard-authentication.md
  59. 1
      src/data/best-practices/api-security/content/validate-content-type.md
  60. 2
      src/data/best-practices/api-security/content/validate-user-input.md
  61. 2
      src/data/best-practices/api-security/content/x-frame-options-deny.md
  62. 2
      src/data/best-practices/aws/content/alerts-as-notifications.md
  63. 2
      src/data/best-practices/aws/content/app-changes-for-aws.md
  64. 2
      src/data/best-practices/aws/content/automate-everything.md
  65. 2
      src/data/best-practices/aws/content/avoid-fs-mounts.md
  66. 2
      src/data/best-practices/aws/content/avoid-multiple-scaling-triggers.md
  67. 2
      src/data/best-practices/aws/content/avoid-server-eips.md
  68. 2
      src/data/best-practices/aws/content/aws-right-choice.md
  69. 2
      src/data/best-practices/aws/content/beware-aws-limits.md
  70. 2
      src/data/best-practices/aws/content/billing-alerts.md
  71. 2
      src/data/best-practices/aws/content/bucket-names-ssl.md
  72. 2
      src/data/best-practices/aws/content/cloudtrail.md
  73. 2
      src/data/best-practices/aws/content/cloudwatch-cli-tools.md
  74. 2
      src/data/best-practices/aws/content/cloudwatch-detailed-monitoring.md
  75. 2
      src/data/best-practices/aws/content/cloudwatch-free-metrics.md
  76. 2
      src/data/best-practices/aws/content/configured-azs-only.md
  77. 2
      src/data/best-practices/aws/content/disable-ssh-access.md
  78. 2
      src/data/best-practices/aws/content/ec2-roles.md
  79. 2
      src/data/best-practices/aws/content/failover-event-subscription.md
  80. 2
      src/data/best-practices/aws/content/group-permissions.md
  81. 2
      src/data/best-practices/aws/content/index.md
  82. 2
      src/data/best-practices/aws/content/key-management-strategy.md
  83. 2
      src/data/best-practices/aws/content/multi-factor-auth-iam.md
  84. 1
      src/data/best-practices/aws/content/pre-warm-elb.md
  85. 2
      src/data/best-practices/aws/content/redundant-across-azs.md
  86. 2
      src/data/best-practices/aws/content/release-eips.md
  87. 2
      src/data/best-practices/aws/content/reserved-instances.md
  88. 2
      src/data/best-practices/aws/content/s3-hive-results.md
  89. 2
      src/data/best-practices/aws/content/scale-down-events.md
  90. 2
      src/data/best-practices/aws/content/scale-horizontally.md
  91. 2
      src/data/best-practices/aws/content/security-audit.md
  92. 2
      src/data/best-practices/aws/content/tag-everything.md
  93. 2
      src/data/best-practices/aws/content/terminate-ssl.md
  94. 2
      src/data/best-practices/aws/content/termination-protection.md
  95. 2
      src/data/best-practices/aws/content/tools-for-logs.md
  96. 2
      src/data/best-practices/aws/content/use-alias-records.md
  97. 1
      src/data/best-practices/aws/content/use-iam-acount.md
  98. 2
      src/data/best-practices/aws/content/use-iam-roles.md
  99. 2
      src/data/best-practices/frontend-performance/content/analyse-stylesheets-complexity.md
  100. 2
      src/data/best-practices/frontend-performance/content/analyze-js-for-perf-issues.md
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,7 @@
app-dist
dist
.idea
.github
public
node_modules
pnpm-lock.yaml

@ -26,7 +26,7 @@ export default defineConfig({
'https://github.com/kamranahmedse', 'https://github.com/kamranahmedse',
'https://thenewstack.io', 'https://thenewstack.io',
'https://cs.fyi', 'https://cs.fyi',
'https://roadmap.sh' 'https://roadmap.sh',
]; ];
if (whiteListedStarts.some((start) => href.startsWith(start))) { if (whiteListedStarts.some((start) => href.startsWith(start))) {

@ -3,7 +3,10 @@ const path = require('path');
const CONTENT_DIR = path.join(__dirname, '../content'); const CONTENT_DIR = path.join(__dirname, '../content');
// Directory containing the best-practices // Directory containing the best-practices
const BEST_PRACTICE_CONTENT_DIR = path.join(__dirname, '../src/data/best-practices'); const BEST_PRACTICE_CONTENT_DIR = path.join(
__dirname,
'../src/data/best-practices'
);
const bestPracticeId = process.argv[2]; const bestPracticeId = process.argv[2];
const allowedBestPracticeId = fs.readdirSync(BEST_PRACTICE_CONTENT_DIR); const allowedBestPracticeId = fs.readdirSync(BEST_PRACTICE_CONTENT_DIR);
@ -28,7 +31,10 @@ if (!bestPracticeDirName) {
process.exit(1); process.exit(1);
} }
const bestPracticeDirPath = path.join(BEST_PRACTICE_CONTENT_DIR, bestPracticeDirName); const bestPracticeDirPath = path.join(
BEST_PRACTICE_CONTENT_DIR,
bestPracticeDirName
);
const bestPracticeContentDirPath = path.join( const bestPracticeContentDirPath = path.join(
BEST_PRACTICE_CONTENT_DIR, BEST_PRACTICE_CONTENT_DIR,
bestPracticeDirName, bestPracticeDirName,
@ -37,7 +43,9 @@ const bestPracticeContentDirPath = path.join(
// If best practice content already exists do not proceed as it would override the files // If best practice content already exists do not proceed as it would override the files
if (fs.existsSync(bestPracticeContentDirPath)) { if (fs.existsSync(bestPracticeContentDirPath)) {
console.error(`Best Practice content already exists @ ${bestPracticeContentDirPath}`); console.error(
`Best Practice content already exists @ ${bestPracticeContentDirPath}`
);
process.exit(1); process.exit(1);
} }
@ -51,7 +59,11 @@ function prepareDirTree(control, dirTree) {
const controlName = control?.properties?.controlName || ''; const controlName = control?.properties?.controlName || '';
// No directory for a group without control name // No directory for a group without control name
if (!controlName || controlName.startsWith('check:') || controlName.startsWith('ext_link:')) { if (
!controlName ||
controlName.startsWith('check:') ||
controlName.startsWith('ext_link:')
) {
return; return;
} }
@ -76,7 +88,10 @@ function prepareDirTree(control, dirTree) {
return { dirTree }; return { dirTree };
} }
const bestPractice = require(path.join(__dirname, `../public/jsons/best-practices/${bestPracticeId}`)); const bestPractice = require(path.join(
__dirname,
`../public/jsons/best-practices/${bestPracticeId}`
));
const controls = bestPractice.mockup.controls.control; const controls = bestPractice.mockup.controls.control;
// Prepare the dir tree that we will be creating // Prepare the dir tree that we will be creating
@ -129,11 +144,7 @@ function createDirTree(parentDir, dirTree, filePaths = {}) {
// For each of the directory names, create a // For each of the directory names, create a
// directory inside the given directory // directory inside the given directory
childrenDirNames.forEach((dirName) => { childrenDirNames.forEach((dirName) => {
createDirTree( createDirTree(path.join(parentDir, dirName), dirTree[dirName], filePaths);
path.join(parentDir, dirName),
dirTree[dirName],
filePaths
);
}); });
return filePaths; return filePaths;
@ -141,4 +152,4 @@ function createDirTree(parentDir, dirTree, filePaths = {}) {
// Create directories and get back the paths for created directories // Create directories and get back the paths for created directories
createDirTree(bestPracticeContentDirPath, dirTree); createDirTree(bestPracticeContentDirPath, dirTree);
console.log('Created best practice content directory structure'); console.log('Created best practice content directory structure');

@ -1,4 +1,5 @@
## CLI Tools ## CLI Tools
> A bunch of CLI scripts to make the development easier > A bunch of CLI scripts to make the development easier
## `roadmap-links.cjs` ## `roadmap-links.cjs`
@ -34,5 +35,3 @@ For the content skeleton to be generated, we should have proper grouping, and th
- Assign the name to the groups. - Assign the name to the groups.
- Group names have the format of `[sort]-[slug]` e.g. `100-internet`. Each group name should start with a number starting from 100 which helps with sorting of the directories and the files. Groups at the same level have the sequential sorting information. - Group names have the format of `[sort]-[slug]` e.g. `100-internet`. Each group name should start with a number starting from 100 which helps with sorting of the directories and the files. Groups at the same level have the sequential sorting information.
- Each groups children have a separate group and have the name similar to `[sort]-[parent-slug]:[child-slug]` where sort refers to the sorting of the `child-slug` and not the parent. Also parent-slug does not need to have the sorting information as a part of slug e.g. if parent was `100-internet` the children would be `100-internet:how-does-the-internet-work`, `101-internet:what-is-http`, `102-internet:browsers`. - Each groups children have a separate group and have the name similar to `[sort]-[parent-slug]:[child-slug]` where sort refers to the sorting of the `child-slug` and not the parent. Also parent-slug does not need to have the sorting information as a part of slug e.g. if parent was `100-internet` the children would be `100-internet:how-does-the-internet-work`, `101-internet:what-is-http`, `102-internet:browsers`.

@ -95,7 +95,9 @@ async function run() {
const roadmapJson = require(path.join(ROADMAP_JSON_DIR, `${roadmapId}.json`)); const roadmapJson = require(path.join(ROADMAP_JSON_DIR, `${roadmapId}.json`));
const groups = roadmapJson?.mockup?.controls?.control?.filter( const groups = roadmapJson?.mockup?.controls?.control?.filter(
(control) => control.typeID === '__group__' && !control.properties?.controlName?.startsWith('ext_link') (control) =>
control.typeID === '__group__' &&
!control.properties?.controlName?.startsWith('ext_link')
); );
if (!OPEN_AI_API_KEY) { if (!OPEN_AI_API_KEY) {
@ -106,8 +108,9 @@ async function run() {
for (let group of groups) { for (let group of groups) {
const topicId = group?.properties?.controlName; const topicId = group?.properties?.controlName;
const topicTitle = group?.children?.controls?.control?.find((control) => control?.typeID === 'Label')?.properties const topicTitle = group?.children?.controls?.control?.find(
?.text; (control) => control?.typeID === 'Label'
)?.properties?.text;
const currTopicUrl = topicId.replace(/^\d+-/g, '/').replace(/:/g, '/'); const currTopicUrl = topicId.replace(/^\d+-/g, '/').replace(/:/g, '/');
const contentFilePath = topicUrlToPathMapping[currTopicUrl]; const contentFilePath = topicUrlToPathMapping[currTopicUrl];

@ -82,7 +82,10 @@ function prepareDirTree(control, dirTree, dirSortOrders) {
return { dirTree, dirSortOrders }; return { dirTree, dirSortOrders };
} }
const roadmap = require(path.join(__dirname, `../public/jsons/roadmaps/${roadmapId}`)); const roadmap = require(path.join(
__dirname,
`../public/jsons/roadmaps/${roadmapId}`
));
const controls = roadmap.mockup.controls.control; const controls = roadmap.mockup.controls.control;
// Prepare the dir tree that we will be creating and also calculate the sort orders // Prepare the dir tree that we will be creating and also calculate the sort orders

@ -27,15 +27,24 @@ function populatePageAds({
const isConfiguredActive = isActive.toLowerCase() === 'yes'; const isConfiguredActive = isActive.toLowerCase() === 'yes';
const currentDate = new Date(); const currentDate = new Date();
const isDateInRange = currentDate >= new Date(startDate) && currentDate <= new Date(endDate); const isDateInRange =
currentDate >= new Date(startDate) && currentDate <= new Date(endDate);
const shouldShowAd = isConfiguredActive && isDateInRange; const shouldShowAd = isConfiguredActive && isDateInRange;
const urlPart = pageUrl.replace('https://roadmap.sh/', '').replace(/\?.+?$/, ''); const urlPart = pageUrl
.replace('https://roadmap.sh/', '')
.replace(/\?.+?$/, '');
const parentDir = urlPart.startsWith('best-practices/') ? 'best-practices' : 'roadmaps'; const parentDir = urlPart.startsWith('best-practices/')
? 'best-practices'
: 'roadmaps';
const pageId = urlPart.replace(`${parentDir}/`, ''); const pageId = urlPart.replace(`${parentDir}/`, '');
const pageFilePath = path.join(__dirname, `../src/data/${parentDir}`, `${pageId}/${pageId}.md`); const pageFilePath = path.join(
__dirname,
`../src/data/${parentDir}`,
`${pageId}/${pageId}.md`
);
if (!fs.existsSync(pageFilePath)) { if (!fs.existsSync(pageFilePath)) {
console.error(`Page file not found: ${pageFilePath}`); console.error(`Page file not found: ${pageFilePath}`);
@ -48,7 +57,9 @@ function populatePageAds({
const frontMatterRegex = /---\n([\s\S]*?)\n---/; const frontMatterRegex = /---\n([\s\S]*?)\n---/;
const existingFrontmatter = pageFileContent.match(frontMatterRegex)[1]; const existingFrontmatter = pageFileContent.match(frontMatterRegex)[1];
const contentWithoutFrontmatter = pageFileContent.replace(frontMatterRegex, ``).trim(); const contentWithoutFrontmatter = pageFileContent
.replace(frontMatterRegex, ``)
.trim();
let frontmatterObj = yaml.load(existingFrontmatter); let frontmatterObj = yaml.load(existingFrontmatter);
delete frontmatterObj.sponsor; delete frontmatterObj.sponsor;
@ -77,7 +88,11 @@ function populatePageAds({
frontmatterObj = Object.fromEntries(frontmatterValues); frontmatterObj = Object.fromEntries(frontmatterValues);
} }
const newFrontmatter = yaml.dump(frontmatterObj, { lineWidth: 10000, forceQuotes: true, quotingType: '"' }); const newFrontmatter = yaml.dump(frontmatterObj, {
lineWidth: 10000,
forceQuotes: true,
quotingType: '"',
});
const newContent = `---\n${newFrontmatter}---\n\n${contentWithoutFrontmatter}`; const newContent = `---\n${newFrontmatter}---\n\n${contentWithoutFrontmatter}`;
fs.writeFileSync(pageFilePath, newContent, 'utf8'); fs.writeFileSync(pageFilePath, newContent, 'utf8');

@ -14,21 +14,21 @@ appearance, race, religion, or sexual identity and orientation.
Examples of behavior that contributes to creating a positive environment Examples of behavior that contributes to creating a positive environment
include: include:
* Using welcoming and inclusive language - Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences - Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism - Gracefully accepting constructive criticism
* Focusing on what is best for the community - Focusing on what is best for the community
* Showing empathy towards other community members - Showing empathy towards other community members
Examples of unacceptable behavior by participants include: Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or - The use of sexualized language or imagery and unwelcome sexual attention or
advances advances
* Trolling, insulting/derogatory comments, and personal or political attacks - Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment - Public or private harassment
* Publishing others' private information, such as a physical or electronic - Publishing others' private information, such as a physical or electronic
address, without explicit permission address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a - Other conduct which could reasonably be considered inappropriate in a
professional setting professional setting
## Our Responsibilities ## Our Responsibilities

@ -8,6 +8,7 @@
"start": "astro dev", "start": "astro dev",
"build": "astro build", "build": "astro build",
"preview": "astro preview", "preview": "astro preview",
"format": "prettier --write .",
"astro": "astro", "astro": "astro",
"deploy": "NODE_DEBUG=gh-pages gh-pages -d dist -t", "deploy": "NODE_DEBUG=gh-pages gh-pages -d dist -t",
"compress:jsons": "node bin/compress-jsons.cjs", "compress:jsons": "node bin/compress-jsons.cjs",

@ -100,7 +100,7 @@ const config: PlaywrightTestConfig = {
/* Run your local dev server before starting the tests */ /* Run your local dev server before starting the tests */
webServer: { webServer: {
command: 'npm run dev', command: 'npm run dev',
url: "http://localhost:3000", url: 'http://localhost:3000',
reuseExistingServer: !process.env.CI, reuseExistingServer: !process.env.CI,
}, },
}; };

File diff suppressed because it is too large Load Diff

@ -27,8 +27,13 @@ export async function serializeSitemap(item) {
'https://roadmap.sh/best-practices', 'https://roadmap.sh/best-practices',
'https://roadmap.sh/guides', 'https://roadmap.sh/guides',
'https://roadmap.sh/videos', 'https://roadmap.sh/videos',
...(await getRoadmapIds()).flatMap((id) => [`https://roadmap.sh/${id}`, `https://roadmap.sh/${id}/topics`]), ...(await getRoadmapIds()).flatMap((id) => [
...(await getBestPracticesIds()).map((id) => `https://roadmap.sh/best-practices/${id}`), `https://roadmap.sh/${id}`,
`https://roadmap.sh/${id}/topics`,
]),
...(await getBestPracticesIds()).map(
(id) => `https://roadmap.sh/best-practices/${id}`
),
]; ];
// Roadmaps and other high priority pages // Roadmaps and other high priority pages
@ -44,7 +49,10 @@ export async function serializeSitemap(item) {
} }
// Guide and video pages // Guide and video pages
if (item.url.startsWith('https://roadmap.sh/guides') || item.url.startsWith('https://roadmap.sh/videos')) { if (
item.url.startsWith('https://roadmap.sh/guides') ||
item.url.startsWith('https://roadmap.sh/videos')
) {
return { return {
...item, ...item,
// @ts-ignore // @ts-ignore

@ -15,9 +15,12 @@ export class Topic {
this.activeTopicId = null; this.activeTopicId = null;
this.handleRoadmapTopicClick = this.handleRoadmapTopicClick.bind(this); this.handleRoadmapTopicClick = this.handleRoadmapTopicClick.bind(this);
this.handleBestPracticeTopicClick = this.handleBestPracticeTopicClick.bind(this); this.handleBestPracticeTopicClick =
this.handleBestPracticeTopicToggle = this.handleBestPracticeTopicToggle.bind(this); this.handleBestPracticeTopicClick.bind(this);
this.handleBestPracticeTopicPending = this.handleBestPracticeTopicPending.bind(this); this.handleBestPracticeTopicToggle =
this.handleBestPracticeTopicToggle.bind(this);
this.handleBestPracticeTopicPending =
this.handleBestPracticeTopicPending.bind(this);
this.close = this.close.bind(this); this.close = this.close.bind(this);
this.resetDOM = this.resetDOM.bind(this); this.resetDOM = this.resetDOM.bind(this);
@ -178,7 +181,10 @@ export class Topic {
this.resetDOM(); this.resetDOM();
const topicUrl = `/best-practices/${bestPracticeId}/${topicId.replaceAll(':', '/')}`; const topicUrl = `/best-practices/${bestPracticeId}/${topicId.replaceAll(
':',
'/'
)}`;
this.renderTopicFromUrl(topicUrl).then(() => null); this.renderTopicFromUrl(topicUrl).then(() => null);
} }
@ -210,24 +216,30 @@ export class Topic {
const matchingElements = []; const matchingElements = [];
// Elements having sort order in the beginning of the group id // Elements having sort order in the beginning of the group id
document.querySelectorAll(`[data-group-id$="-${topicId}"]`).forEach((element) => { document
const foundGroupId = element?.dataset?.groupId || ''; .querySelectorAll(`[data-group-id$="-${topicId}"]`)
const validGroupRegex = new RegExp(`^\\d+-${topicId}$`); .forEach((element) => {
const foundGroupId = element?.dataset?.groupId || '';
if (validGroupRegex.test(foundGroupId)) { const validGroupRegex = new RegExp(`^\\d+-${topicId}$`);
matchingElements.push(element);
} if (validGroupRegex.test(foundGroupId)) {
}); matchingElements.push(element);
}
});
// Elements with exact match of the topic id // Elements with exact match of the topic id
document.querySelectorAll(`[data-group-id="${topicId}"]`).forEach((element) => { document
matchingElements.push(element); .querySelectorAll(`[data-group-id="${topicId}"]`)
}); .forEach((element) => {
matchingElements.push(element);
});
// Matching "check:XXXX" box of the topic // Matching "check:XXXX" box of the topic
document.querySelectorAll(`[data-group-id="check:${topicId}"]`).forEach((element) => { document
matchingElements.push(element); .querySelectorAll(`[data-group-id="check:${topicId}"]`)
}); .forEach((element) => {
matchingElements.push(element);
});
return matchingElements; return matchingElements;
} }
@ -258,29 +270,44 @@ export class Topic {
return; return;
} }
const isClickedDone = e.target.id === this.markTopicDoneId || e.target.closest(`#${this.markTopicDoneId}`); const isClickedDone =
e.target.id === this.markTopicDoneId ||
e.target.closest(`#${this.markTopicDoneId}`);
if (isClickedDone) { if (isClickedDone) {
this.markAsDone(this.activeTopicId); this.markAsDone(this.activeTopicId);
this.close(); this.close();
} }
const isClickedPending = e.target.id === this.markTopicPendingId || e.target.closest(`#${this.markTopicPendingId}`); const isClickedPending =
e.target.id === this.markTopicPendingId ||
e.target.closest(`#${this.markTopicPendingId}`);
if (isClickedPending) { if (isClickedPending) {
this.markAsPending(this.activeTopicId); this.markAsPending(this.activeTopicId);
this.close(); this.close();
} }
const isClickedClose = e.target.id === this.closeTopicId || e.target.closest(`#${this.closeTopicId}`); const isClickedClose =
e.target.id === this.closeTopicId ||
e.target.closest(`#${this.closeTopicId}`);
if (isClickedClose) { if (isClickedClose) {
this.close(); this.close();
} }
} }
init() { init() {
window.addEventListener('best-practice.topic.click', this.handleBestPracticeTopicClick); window.addEventListener(
window.addEventListener('best-practice.topic.toggle', this.handleBestPracticeTopicToggle); 'best-practice.topic.click',
this.handleBestPracticeTopicClick
window.addEventListener('roadmap.topic.click', this.handleRoadmapTopicClick); );
window.addEventListener(
'best-practice.topic.toggle',
this.handleBestPracticeTopicToggle
);
window.addEventListener(
'roadmap.topic.click',
this.handleRoadmapTopicClick
);
window.addEventListener('click', this.handleOverlayClick); window.addEventListener('click', this.handleOverlayClick);
window.addEventListener('contextmenu', this.rightClickListener); window.addEventListener('contextmenu', this.rightClickListener);

@ -1,37 +1,36 @@
--- ---
jsonUrl: "/jsons/best-practices/api-security.json" jsonUrl: '/jsons/best-practices/api-security.json'
pdfUrl: "/pdfs/best-practices/api-security.pdf" pdfUrl: '/pdfs/best-practices/api-security.pdf'
order: 2 order: 2
briefTitle: "API Security" briefTitle: 'API Security'
briefDescription: "API Security Best Practices" briefDescription: 'API Security Best Practices'
isNew: true isNew: true
isUpcoming: false isUpcoming: false
title: "API Security Best Practices" title: 'API Security Best Practices'
description: "Detailed list of best practices to make your APIs secure" description: 'Detailed list of best practices to make your APIs secure'
dimensions: dimensions:
width: 968 width: 968
height: 1543.39 height: 1543.39
sponsor: sponsor:
url: "https://www.getambassador.io/products/edge-stack-api-gateway?utm_source=roadmap-sh&utm_medium=edge-stack-page&utm_campaign=new-account" url: 'https://www.getambassador.io/products/edge-stack-api-gateway?utm_source=roadmap-sh&utm_medium=edge-stack-page&utm_campaign=new-account'
title: "Featured Product" title: 'Featured Product'
imageUrl: "https://i.imgur.com/e5fdI0q.png" imageUrl: 'https://i.imgur.com/e5fdI0q.png'
description: "Get your Kubernetes API Gateway up and running in 5 minutes with Ambassador Edge Stack!" description: 'Get your Kubernetes API Gateway up and running in 5 minutes with Ambassador Edge Stack!'
event: event:
category: "SponsorClick" category: 'SponsorClick'
action: "Ambassador Redirect" action: 'Ambassador Redirect'
label: "API Security / Ambassador Link" label: 'API Security / Ambassador Link'
schema: schema:
headline: "API Security Best Practices" headline: 'API Security Best Practices'
description: "Detailed list of best practices to make your APIs secure. Each best practice carries further details and how to implement that best practice." description: 'Detailed list of best practices to make your APIs secure. Each best practice carries further details and how to implement that best practice.'
imageUrl: "https://roadmap.sh/best-practices/api-security.png" imageUrl: 'https://roadmap.sh/best-practices/api-security.png'
datePublished: "2023-02-21" datePublished: '2023-02-21'
dateModified: "2023-02-21" dateModified: '2023-02-21'
seo: seo:
title: "API Security Best Practices" title: 'API Security Best Practices'
description: "Detailed list of best practices to make your APIs secure. Each best practice carries further details and how to implement that best practice." description: 'Detailed list of best practices to make your APIs secure. Each best practice carries further details and how to implement that best practice.'
keywords: keywords:
- "API Security" - 'API Security'
- "API Security Best Practices" - 'API Security Best Practices'
- "API Security Checklist" - 'API Security Checklist'
--- ---

@ -12,4 +12,4 @@ An API gateway can make your APIs more secure by providing a centralized point o
- Logging and monitoring: An API gateway can provide centralized logging and monitoring of API traffic, helping to identify and respond to security threats and other issues. - Logging and monitoring: An API gateway can provide centralized logging and monitoring of API traffic, helping to identify and respond to security threats and other issues.
- Integration with security tools: An API gateway can be integrated with security tools such as WAFs, SIEMs, and other security tools to provide additional layers of protection. - Integration with security tools: An API gateway can be integrated with security tools such as WAFs, SIEMs, and other security tools to provide additional layers of protection.

@ -12,4 +12,4 @@ Here are some examples of established authentication mechanisms that you can use
- Password hashing algorithms: Password hashing algorithms like bcrypt and scrypt are widely used to securely store and protect user passwords. These algorithms ensure that even if an attacker gains access to the password database, they will not be able to easily recover the passwords. - Password hashing algorithms: Password hashing algorithms like bcrypt and scrypt are widely used to securely store and protect user passwords. These algorithms ensure that even if an attacker gains access to the password database, they will not be able to easily recover the passwords.
- Two-factor authentication (2FA): 2FA is an authentication mechanism that requires users to provide two forms of identification to access their accounts. This typically involves something the user knows (like a password) and something the user has (like a mobile device or security key). Many services and applications now offer 2FA as an additional security measure. - Two-factor authentication (2FA): 2FA is an authentication mechanism that requires users to provide two forms of identification to access their accounts. This typically involves something the user knows (like a password) and something the user has (like a mobile device or security key). Many services and applications now offer 2FA as an additional security measure.

@ -6,4 +6,4 @@ Sending tokens in the query or body parameters is generally not recommended beca
Additionally, sending tokens in query or body parameters can make them more vulnerable to cross-site request forgery (CSRF) attacks. In a CSRF attack, an attacker can trick a user into submitting a request that includes their authentication token, which the attacker can then use to impersonate the user and gain access to their account. Additionally, sending tokens in query or body parameters can make them more vulnerable to cross-site request forgery (CSRF) attacks. In a CSRF attack, an attacker can trick a user into submitting a request that includes their authentication token, which the attacker can then use to impersonate the user and gain access to their account.
By contrast, using the `Authorization` header to send tokens helps to ensure that the tokens are not logged or cached by intermediary systems, and it can also help to protect against CSRF attacks by allowing the server to validate the token before processing the request. By contrast, using the `Authorization` header to send tokens helps to ensure that the tokens are not logged or cached by intermediary systems, and it can also help to protect against CSRF attacks by allowing the server to validate the token before processing the request.

@ -2,4 +2,4 @@
> Avoid HTTP blocking if you are using huge amount of data by moving the HTTP heavy operations to background jobs or asynchronous tasks. > Avoid HTTP blocking if you are using huge amount of data by moving the HTTP heavy operations to background jobs or asynchronous tasks.
HTTP blocking is a common issue in web applications. It occurs when the application is unable to process incoming HTTP requests due to a large number of requests or a large amount of data. This can lead to the application becoming unresponsive and the server crashing. This can be prevented by moving HTTP heavy operations to background jobs or asynchronous tasks. You can use a message queue to queue the requests and process them in the background. This will allow the application to continue processing other requests while the heavy operations are being processed in the background. HTTP blocking is a common issue in web applications. It occurs when the application is unable to process incoming HTTP requests due to a large number of requests or a large amount of data. This can lead to the application becoming unresponsive and the server crashing. This can be prevented by moving HTTP heavy operations to background jobs or asynchronous tasks. You can use a message queue to queue the requests and process them in the background. This will allow the application to continue processing other requests while the heavy operations are being processed in the background.

@ -2,4 +2,4 @@
> Ensure that you aren't logging any sensitive data. > Ensure that you aren't logging any sensitive data.
Make sure that you are not logging any sensitive data such as passwords, credit card numbers, or personal information. This is because logging sensitive data can expose it to attackers, allowing them to gain unauthorized access to your system or data. Additionally, logging sensitive data can violate data privacy laws and regulations, exposing you to legal liability. Make sure that you are not logging any sensitive data such as passwords, credit card numbers, or personal information. This is because logging sensitive data can expose it to attackers, allowing them to gain unauthorized access to your system or data. Additionally, logging sensitive data can violate data privacy laws and regulations, exposing you to legal liability.

@ -2,4 +2,4 @@
> Avoid user’s personal ID in the resource URLs e.g. users/242/orders > Avoid user’s personal ID in the resource URLs e.g. users/242/orders
User's own resource ID should be avoided. Use `/me/orders` instead of `/user/654321/orders`. This will help avoid the risk of exposing the user’s personal ID that can be used for further attacks. User's own resource ID should be avoided. Use `/me/orders` instead of `/user/654321/orders`. This will help avoid the risk of exposing the user’s personal ID that can be used for further attacks.

@ -2,4 +2,4 @@
> Only return the data that is needed for the client to function. > Only return the data that is needed for the client to function.
Returning only the data that is needed for the client to function is an important best practice for API security. This is because limiting the amount of data that is returned reduces the amount of sensitive information that is exposed. By only returning the necessary data, you can help prevent security vulnerabilities such as data leakage, injection attacks, and other types of attacks that rely on exposing too much information. Additionally, reducing the amount of data returned can improve the performance of your API by reducing the amount of data that needs to be processed and transmitted. Returning only the data that is needed for the client to function is an important best practice for API security. This is because limiting the amount of data that is returned reduces the amount of sensitive information that is exposed. By only returning the necessary data, you can help prevent security vulnerabilities such as data leakage, injection attacks, and other types of attacks that rely on exposing too much information. Additionally, reducing the amount of data returned can improve the performance of your API by reducing the amount of data that needs to be processed and transmitted.

@ -2,4 +2,4 @@
> Use CDN for file uploads > Use CDN for file uploads
Using a Content Delivery Network (CDN) for file uploads can make an API more secure by offloading the file upload traffic from the API server and reducing the risk of DDoS attacks. Using a Content Delivery Network (CDN) for file uploads can make an API more secure by offloading the file upload traffic from the API server and reducing the risk of DDoS attacks.

@ -10,4 +10,4 @@ Using centralized logins for all services and components is important for severa
- Centralized logins make it easier to enforce security policies across different services and components, ensuring that only authorized users can access sensitive data or perform certain actions. - Centralized logins make it easier to enforce security policies across different services and components, ensuring that only authorized users can access sensitive data or perform certain actions.
To use centralized logins, you need to set up a single sign-on (SSO) system that enables users to authenticate once and then access multiple services without having to provide credentials again. This can be done using protocols like OAuth or SAML, which enable secure authentication and authorization across different applications and services. Once set up, you can use centralized logging tools like ELK stack, Splunk, or Graylog to collect logs from different services and components and analyze them in one place. This enables you to quickly identify and respond to security threats or anomalies. To use centralized logins, you need to set up a single sign-on (SSO) system that enables users to authenticate once and then access multiple services without having to provide credentials again. This can be done using protocols like OAuth or SAML, which enable secure authentication and authorization across different applications and services. Once set up, you can use centralized logging tools like ELK stack, Splunk, or Graylog to collect logs from different services and components and analyze them in one place. This enables you to quickly identify and respond to security threats or anomalies.

@ -4,4 +4,4 @@
Vulnerabilities in third-party libraries and components can be exploited by attackers to gain access to your system or data. These vulnerabilities can be introduced through outdated or insecure dependencies that have not been updated with the latest security patches. Vulnerabilities in third-party libraries and components can be exploited by attackers to gain access to your system or data. These vulnerabilities can be introduced through outdated or insecure dependencies that have not been updated with the latest security patches.
By regularly checking for vulnerabilities and keeping your dependencies up to date, you can ensure that your API is not susceptible to known security risks. This can be done by using automated tools or services that scan your codebase and provide reports on any vulnerabilities found in your dependencies. By addressing these vulnerabilities promptly, you can reduce the risk of your API being compromised by attackers. By regularly checking for vulnerabilities and keeping your dependencies up to date, you can ensure that your API is not susceptible to known security risks. This can be done by using automated tools or services that scan your codebase and provide reports on any vulnerabilities found in your dependencies. By addressing these vulnerabilities promptly, you can reduce the risk of your API being compromised by attackers.

@ -2,4 +2,4 @@
> Use a code review process and disregard self-approval. > Use a code review process and disregard self-approval.
Having a good code review process allows for additional sets of eyes to review the code and identify potential security issues or vulnerabilities. A code review process involves other team members reviewing the code to ensure it follows best practices and is secure. Disregarding self-approval means that the developer who wrote the code should not be the only one responsible for approving it for release. This helps to catch potential mistakes or oversights before the code is deployed, reducing the risk of security breaches or other issues. Having a good code review process allows for additional sets of eyes to review the code and identify potential security issues or vulnerabilities. A code review process involves other team members reviewing the code to ensure it follows best practices and is secure. Disregarding self-approval means that the developer who wrote the code should not be the only one responsible for approving it for release. This helps to catch potential mistakes or oversights before the code is deployed, reducing the risk of security breaches or other issues.

@ -2,4 +2,4 @@
> Send `Content-Security-Policy: default-src 'none'` header. > Send `Content-Security-Policy: default-src 'none'` header.
Sending the `Content-Security-Policy: default-src 'none'` header is a security best practice that helps prevent cross-site scripting (XSS) attacks. This header tells the browser to not allow any resources to be loaded from external sources, such as scripts, stylesheets, or images. It only allows resources that are explicitly whitelisted in the CSP header, such as scripts or stylesheets hosted on your own domain. This can help prevent malicious actors from injecting code into your web pages via XSS attacks, as the browser will not execute any scripts or load any resources that are not explicitly allowed by the CSP policy. Sending the `Content-Security-Policy: default-src 'none'` header is a security best practice that helps prevent cross-site scripting (XSS) attacks. This header tells the browser to not allow any resources to be loaded from external sources, such as scripts, stylesheets, or images. It only allows resources that are explicitly whitelisted in the CSP header, such as scripts or stylesheets hosted on your own domain. This can help prevent malicious actors from injecting code into your web pages via XSS attacks, as the browser will not execute any scripts or load any resources that are not explicitly allowed by the CSP policy.

@ -2,4 +2,4 @@
> Make sure to turn the debug mode off in production > Make sure to turn the debug mode off in production
Debug mode is a feature that is used to help developers debug their code. It is not meant to be used in production. It can expose sensitive information about the application and the server it is running on. Make sure to turn debug mode off in production. Debug mode is a feature that is used to help developers debug their code. It is not meant to be used in production. It can expose sensitive information about the application and the server it is running on. Make sure to turn debug mode off in production.

@ -4,4 +4,4 @@
Directory listings are a feature of web servers that allow users to view the contents of a directory on a server. By default, web servers often have directory listings enabled, which means that anyone who has access to the server can see all the files and directories in a given folder. Directory listings are a feature of web servers that allow users to view the contents of a directory on a server. By default, web servers often have directory listings enabled, which means that anyone who has access to the server can see all the files and directories in a given folder.
Turning off directory listings is important for API security because it prevents attackers from gaining access to sensitive files and directories on the server. If directory listings are enabled and an attacker gains access to the server, they can easily view and download any files that are not properly protected. By disabling directory listings, you can ensure that only authorized users can access the files and directories on the server. Turning off directory listings is important for API security because it prevents attackers from gaining access to sensitive files and directories on the server. If directory listings are enabled and an attacker gains access to the server, they can easily view and download any files that are not properly protected. By disabling directory listings, you can ensure that only authorized users can access the files and directories on the server.

@ -2,4 +2,4 @@
> Disable entity expansion if using XML, YML or any other language > Disable entity expansion if using XML, YML or any other language
Disabling entity expansion is important when using XML, YAML, or any other language that allows entities because it helps prevent XXE (XML External Entity) or YAML tag injection attacks. In these attacks, attacker normally injects some sort of custom code in the input to perform attacks against the application.. By disabling entity expansion, the input cannot be manipulated in this way, reducing the risk of such attacks. Disabling entity expansion is important when using XML, YAML, or any other language that allows entities because it helps prevent XXE (XML External Entity) or YAML tag injection attacks. In these attacks, attacker normally injects some sort of custom code in the input to perform attacks against the application.. By disabling entity expansion, the input cannot be manipulated in this way, reducing the risk of such attacks.

@ -4,4 +4,4 @@
If the XML parser is vulnerable to XXE attacks, the attacker can use this vulnerability to read files on the server, perform SSRF attacks, and more. This can lead to the disclosure of sensitive information, denial of service, and other attacks. If the XML parser is vulnerable to XXE attacks, the attacker can use this vulnerability to read files on the server, perform SSRF attacks, and more. This can lead to the disclosure of sensitive information, denial of service, and other attacks.
XXE (XML External Entity) attack is a type of attack that targets applications that parse XML input from untrusted sources. In this attack, an attacker injects a malicious XML payload. This payload can contain external entities that the attacker can use to retrieve sensitive data, execute remote code, or launch denial of service attacks. XXE attacks can be prevented by disabling external entity processing or by validating and sanitizing the XML input before parsing it. XXE (XML External Entity) attack is a type of attack that targets applications that parse XML input from untrusted sources. In this attack, an attacker injects a malicious XML payload. This payload can contain external entities that the attacker can use to retrieve sensitive data, execute remote code, or launch denial of service attacks. XXE attacks can be prevented by disabling external entity processing or by validating and sanitizing the XML input before parsing it.

@ -1,6 +1,6 @@
# Endpoint Authentication # Endpoint Authentication
> Check if all the protected endpoints are behind authentication > Check if all the protected endpoints are behind authentication
to avoid broken authentication process > to avoid broken authentication process
By identifying and fixing broken authentication workflows, the API can prevent attacks such as brute force attacks, credential stuffing, session hijacking, and other authentication-related attacks. This can help ensure that the system is secure and that sensitive data is protected. By identifying and fixing broken authentication workflows, the API can prevent attacks such as brute force attacks, credential stuffing, session hijacking, and other authentication-related attacks. This can help ensure that the system is secure and that sensitive data is protected.

@ -2,4 +2,4 @@
> Always force the `Content-Type` header to be set to relevant MIME type. > Always force the `Content-Type` header to be set to relevant MIME type.
Forcing the content-type for API security is important because it ensures that the client and server are communicating in a mutually agreed-upon format for the data being transmitted. This can prevent attacks such as content spoofing or injection, where an attacker tries to trick the server into processing malicious content by pretending that it is of a different content type. By forcing the content-type to a specific format, the server can validate that the data it is receiving is legitimate and safe to process. Additionally, forcing the content-type can help prevent certain types of parsing errors that could be exploited by attackers. Forcing the content-type for API security is important because it ensures that the client and server are communicating in a mutually agreed-upon format for the data being transmitted. This can prevent attacks such as content spoofing or injection, where an attacker tries to trick the server into processing malicious content by pretending that it is of a different content type. By forcing the content-type to a specific format, the server can validate that the data it is receiving is legitimate and safe to process. Additionally, forcing the content-type can help prevent certain types of parsing errors that could be exploited by attackers.

@ -2,4 +2,4 @@
> You should have a good JWT secret to protect against token tempering as well as avoiding brute force attacks. > You should have a good JWT secret to protect against token tempering as well as avoiding brute force attacks.
A strong secret key should be randomly generated, long, and complex, and should be stored securely and rotated periodically. A strong secret key should be randomly generated, long, and complex, and should be stored securely and rotated periodically.

@ -6,4 +6,4 @@ SSL strip is a type of attack where an attacker intercepts traffic between a cli
In an SSL strip attack, the attacker sets up a man-in-the-middle (MITM) position between the client and the server. When the client initiates a connection with the server, the attacker intercepts the SSL/TLS traffic and removes or replaces the HTTPS links with HTTP links. This can trick the user into thinking they are using a secure connection when in fact, they are not. The attacker can then monitor and manipulate the data transmitted between the client and server. In an SSL strip attack, the attacker sets up a man-in-the-middle (MITM) position between the client and the server. When the client initiates a connection with the server, the attacker intercepts the SSL/TLS traffic and removes or replaces the HTTPS links with HTTP links. This can trick the user into thinking they are using a secure connection when in fact, they are not. The attacker can then monitor and manipulate the data transmitted between the client and server.
HSTS header is a security header that instructs browsers to only access the site over HTTPS. This header is used to prevent SSL Strip attacks. It is a good practice to use HSTS header with SSL. HSTS header is a security header that instructs browsers to only access the site over HTTPS. This header is used to prevent SSL Strip attacks. It is a good practice to use HSTS header with SSL.

@ -2,4 +2,4 @@
> Do not extract the algorithm from the header, use backend. > Do not extract the algorithm from the header, use backend.
Extracting the algorithm from the header of a JWT token can pose a security risk, as an attacker could modify the algorithm and potentially gain unauthorized access. It is therefore recommended to verify the algorithm on the backend rather than extracting it from the header. This can help ensure that the algorithm used to sign and verify the token is secure and has not been tampered with. Extracting the algorithm from the header of a JWT token can pose a security risk, as an attacker could modify the algorithm and potentially gain unauthorized access. It is therefore recommended to verify the algorithm on the backend rather than extracting it from the header. This can help ensure that the algorithm used to sign and verify the token is secure and has not been tampered with.

@ -2,4 +2,4 @@
> Avoid storing sensitive data in JWT payload > Avoid storing sensitive data in JWT payload
Storing sensitive data in a JWT token payload can increase the risk of data breaches and other security incidents. If an attacker is able to obtain or tamper with the token, they could potentially access the sensitive data stored in the payload. Storing sensitive data in a JWT token payload can increase the risk of data breaches and other security incidents. If an attacker is able to obtain or tamper with the token, they could potentially access the sensitive data stored in the payload.

@ -4,4 +4,4 @@
Using agents to monitor all requests, responses, and errors allows for real-time monitoring and detection of any abnormal activity or potential attacks. These agents can be configured to track metrics such as response times, error rates, and usage patterns, which can help identify any anomalies that could be indicative of an attack. By monitoring all requests and responses, the agents can provide visibility into the behavior of the API, which can help identify any potential security vulnerabilities or weaknesses. Additionally, agents can be used to log and analyze all data flowing through the API, which can be useful for debugging and auditing purposes. Using agents to monitor all requests, responses, and errors allows for real-time monitoring and detection of any abnormal activity or potential attacks. These agents can be configured to track metrics such as response times, error rates, and usage patterns, which can help identify any anomalies that could be indicative of an attack. By monitoring all requests and responses, the agents can provide visibility into the behavior of the API, which can help identify any potential security vulnerabilities or weaknesses. Additionally, agents can be used to log and analyze all data flowing through the API, which can be useful for debugging and auditing purposes.
To use agents for monitoring, a dedicated monitoring solution can be deployed alongside the API. This solution can be configured to capture data from all requests and responses, and analyze the data for any anomalies or issues. Agents can be implemented using various monitoring tools and technologies such as agents for application performance monitoring (APM), log monitoring, and network monitoring. The agents should be configured to provide real-time alerts to security teams if any suspicious activity is detected, allowing for immediate action to be taken. To use agents for monitoring, a dedicated monitoring solution can be deployed alongside the API. This solution can be configured to capture data from all requests and responses, and analyze the data for any anomalies or issues. Agents can be implemented using various monitoring tools and technologies such as agents for application performance monitoring (APM), log monitoring, and network monitoring. The agents should be configured to provide real-time alerts to security teams if any suspicious activity is detected, allowing for immediate action to be taken.

@ -4,4 +4,4 @@
You should send the `X-Content-Type-Options: nosniff` header to prevent [MIME type sniffing attacks](https://www.keycdn.com/support/what-is-mime-sniffing) on your web application. This header tells the browser not to override the response content type even if it's not the expected type. For example, if an attacker manages to upload an HTML file with a disguised extension like .jpg, the server may still send the correct content type header for the HTML file. However, some browsers may ignore this header and try to "sniff" the content type based on the actual contents of the file, leading to a potential cross-site scripting (XSS) attack. You should send the `X-Content-Type-Options: nosniff` header to prevent [MIME type sniffing attacks](https://www.keycdn.com/support/what-is-mime-sniffing) on your web application. This header tells the browser not to override the response content type even if it's not the expected type. For example, if an attacker manages to upload an HTML file with a disguised extension like .jpg, the server may still send the correct content type header for the HTML file. However, some browsers may ignore this header and try to "sniff" the content type based on the actual contents of the file, leading to a potential cross-site scripting (XSS) attack.
By sending the `X-Content-Type-Options: nosniff` header, you tell the browser to always trust the provided content type and not try to sniff the content type. This helps to mitigate the risk of attackers exploiting content type mismatches to deliver malicious content to unsuspecting users. By sending the `X-Content-Type-Options: nosniff` header, you tell the browser to always trust the provided content type and not try to sniff the content type. This helps to mitigate the risk of attackers exploiting content type mismatches to deliver malicious content to unsuspecting users.

@ -4,4 +4,4 @@
A stack usually refers to the call stack or execution stack. It is a data structure used by the computer program to manage and keep track of the sequence of function calls, local variables, and other related data during the execution of the program. A stack usually refers to the call stack or execution stack. It is a data structure used by the computer program to manage and keep track of the sequence of function calls, local variables, and other related data during the execution of the program.
A non-executable stack is a security mechanism that prevents malicious code from being executed by preventing the stack memory from being executed as code. This helps to prevent attacks such as buffer overflow attacks, where an attacker tries to overwrite the return address on the stack to redirect the program to execute malicious code. By using non-executable stacks, the program can keep the stack separate from executable code and help prevent these types of attacks. A non-executable stack is a security mechanism that prevents malicious code from being executed by preventing the stack memory from being executed as code. This helps to prevent attacks such as buffer overflow attacks, where an attacker tries to overwrite the return address on the stack to redirect the program to execute malicious code. By using non-executable stacks, the program can keep the stack separate from executable code and help prevent these types of attacks.

@ -6,4 +6,4 @@ In OAuth, `redirect_uri` is a parameter that specifies the URI (Uniform Resource
It is important to validate the `redirect_uri` on the server-side to prevent attacks such as open redirection attacks. In an open redirection attack, an attacker can modify the `redirect_uri` parameter to redirect the user to a malicious website. By validating the `redirect_uri` on the server-side, you can ensure that the redirect URI is a valid and authorized URI for the client application. It is important to validate the `redirect_uri` on the server-side to prevent attacks such as open redirection attacks. In an open redirection attack, an attacker can modify the `redirect_uri` parameter to redirect the user to a malicious website. By validating the `redirect_uri` on the server-side, you can ensure that the redirect URI is a valid and authorized URI for the client application.
Validating the `redirect_uri` on the server-side can also prevent other types of attacks such as phishing attacks or cross-site request forgery (CSRF) attacks. By verifying that the `redirect_uri` matches a predefined list of authorized URIs, you can ensure that the user is redirected to a trusted site after authentication is complete. Validating the `redirect_uri` on the server-side can also prevent other types of attacks such as phishing attacks or cross-site request forgery (CSRF) attacks. By verifying that the `redirect_uri` matches a predefined list of authorized URIs, you can ensure that the user is redirected to a trusted site after authentication is complete.

@ -2,4 +2,4 @@
> Use server-side encryption instead of client-side encryption > Use server-side encryption instead of client-side encryption
Client-side encryption is not recommended because client side codebase can be easily reverse engineered which can lead to the exposure of encryption algorithms. Client-side encryption is not recommended because client side codebase can be easily reverse engineered which can lead to the exposure of encryption algorithms.

@ -2,4 +2,4 @@
> Use UUIDs instead of auto-incrementing integers. UUIDs are globally unique, and are not sequential. They are also more difficult to guess than sequential integers. > Use UUIDs instead of auto-incrementing integers. UUIDs are globally unique, and are not sequential. They are also more difficult to guess than sequential integers.
Use of UUIDs over auto-incrementing IDs prevents attackers from guessing or iterating through resource IDs. UUIDs are randomly generated and contain 128 bits of entropy, making it practically impossible for attackers to guess them. In contrast, autoincrementing IDs can be easily predicted or iterated through, allowing attackers to access or manipulate resources they shouldn't have access to. Additionally, using UUIDs can help prevent information disclosure by hiding the order of resource creation or access. Use of UUIDs over auto-incrementing IDs prevents attackers from guessing or iterating through resource IDs. UUIDs are randomly generated and contain 128 bits of entropy, making it practically impossible for attackers to guess them. In contrast, autoincrementing IDs can be easily predicted or iterated through, allowing attackers to access or manipulate resources they shouldn't have access to. Additionally, using UUIDs can help prevent information disclosure by hiding the order of resource creation or access.

@ -1,5 +1,3 @@
# Proper HTTP Methods # Proper HTTP Methods
Use the proper HTTP method according to the operation: `GET (read)`, `POST (create)`, `PUT/PATCH (replace/update)`, and `DELETE (to delete a record)`, and respond with `405 Method Not Allowed` if the requested method isn't appropriate for the requested resource. Use the proper HTTP method according to the operation: `GET (read)`, `POST (create)`, `PUT/PATCH (replace/update)`, and `DELETE (to delete a record)`, and respond with `405 Method Not Allowed` if the requested method isn't appropriate for the requested resource.

@ -1,10 +1,11 @@
# Proper Response Code # Proper Response Code
> Return the proper status code according to the operation completed. e.g. > Return the proper status code according to the operation completed. e.g.
>
> - `200 OK` > - `200 OK`
> - `400 Bad Request` > - `400 Bad Request`
> - `401 Unauthorized` > - `401 Unauthorized`
> - `405 Method Not Allowed` > - `405 Method Not Allowed`
> - ...etc. > - ...etc.
Returning the proper status code according to the operation completed is important for API security because it allows the client to understand the outcome of their request and take appropriate actions. For example, if the server returns a 401 Unauthorized status code, the client knows that their authentication credentials are incorrect and can prompt the user to re-enter their login details. On the other hand, if the server returns a 200 OK status code even though the request failed, the client may not realize there was an issue and could potentially execute malicious actions or display incorrect data. Providing accurate status codes can help prevent security vulnerabilities and improve the overall reliability and usability of the API. Returning the proper status code according to the operation completed is important for API security because it allows the client to understand the outcome of their request and take appropriate actions. For example, if the server returns a 401 Unauthorized status code, the client knows that their authentication credentials are incorrect and can prompt the user to re-enter their login details. On the other hand, if the server returns a 200 OK status code even though the request failed, the client may not realize there was an issue and could potentially execute malicious actions or display incorrect data. Providing accurate status codes can help prevent security vulnerabilities and improve the overall reliability and usability of the API.

@ -5,4 +5,4 @@ Have a look at the following resources for more information on API security:
- [Collection of Resources for Building APIs](https://github.com/yosriady/awesome-api-devtools) - [Collection of Resources for Building APIs](https://github.com/yosriady/awesome-api-devtools)
- [CS253: Web Security](https://www.youtube.com/watch?v=5JJrJGZ_LjM&list=PL1y1iaEtjSYiiSGVlL1cHsXN_kvJOOhu-) - [CS253: Web Security](https://www.youtube.com/watch?v=5JJrJGZ_LjM&list=PL1y1iaEtjSYiiSGVlL1cHsXN_kvJOOhu-)
- [Securing Web Applications](https://www.youtube.com/watch?v=WlmKwIe9z1Q) - [Securing Web Applications](https://www.youtube.com/watch?v=WlmKwIe9z1Q)
- [MIT 6.858: Computer Systems Security](https://www.youtube.com/watch?v=GqmQg-cszw4&list=PLUl4u3cNGP62K2DjQLRxDNRi0z2IRWnNh) - [MIT 6.858: Computer Systems Security](https://www.youtube.com/watch?v=GqmQg-cszw4&list=PLUl4u3cNGP62K2DjQLRxDNRi0z2IRWnNh)

@ -2,4 +2,4 @@
> Remove fingerprinting headers (i.e. x-powered-by etc) from the HTTP request. > Remove fingerprinting headers (i.e. x-powered-by etc) from the HTTP request.
Fingerprinting headers can be used to identify the web server and its version. This information can be used by attackers to identify vulnerabilities in the web server and exploit them. Fingerprinting headers can be used to identify the web server and its version. This information can be used by attackers to identify vulnerabilities in the web server and exploit them.

@ -3,4 +3,3 @@
> Private APIs should only be accessible from safe listed IPs > Private APIs should only be accessible from safe listed IPs
Private APIs should only be accessible from safe-listed IPs to ensure that only authorized users or systems can access the API. By restricting access to specific IP addresses, you can prevent unauthorized access from external networks or malicious actors. This can help to protect sensitive data and prevent attacks such as DDoS or brute-force attacks. Additionally, restricting access to safe-listed IPs can help to ensure the reliability and performance of the API by preventing excessive traffic from unauthorized sources. Private APIs should only be accessible from safe-listed IPs to ensure that only authorized users or systems can access the API. By restricting access to specific IP addresses, you can prevent unauthorized access from external networks or malicious actors. This can help to protect sensitive data and prevent attacks such as DDoS or brute-force attacks. Additionally, restricting access to safe-listed IPs can help to ensure the reliability and performance of the API by preventing excessive traffic from unauthorized sources.

@ -2,4 +2,4 @@
> Design a rollback solution for deployments. > Design a rollback solution for deployments.
Sometimes deploying a new version of the API can introduce unexpected bugs or issues that were not caught during testing. In such cases, rolling back to the previous version of the API can help to mitigate the impact of the issue and restore the service to a functional state. A well-designed rollback solution can help reduce downtime and minimize the impact on users. Sometimes deploying a new version of the API can introduce unexpected bugs or issues that were not caught during testing. In such cases, rolling back to the previous version of the API can help to mitigate the impact of the issue and restore the service to a functional state. A well-designed rollback solution can help reduce downtime and minimize the impact on users.

@ -2,4 +2,4 @@
> Continuously run security analysis on your code. > Continuously run security analysis on your code.
Continuous security analysis helps identify and address security vulnerabilities in the codebase before they can be exploited by attackers. It involves using automated tools and manual techniques to scan code for potential weaknesses, such as insecure coding practices, configuration errors, and outdated dependencies. By identifying and fixing vulnerabilities early in the development cycle, the risk of a security breach or data loss can be significantly reduced, improving the overall security posture of the system. Continuous security analysis helps identify and address security vulnerabilities in the codebase before they can be exploited by attackers. It involves using automated tools and manual techniques to scan code for potential weaknesses, such as insecure coding practices, configuration errors, and outdated dependencies. By identifying and fixing vulnerabilities early in the development cycle, the risk of a security breach or data loss can be significantly reduced, improving the overall security posture of the system.

@ -4,4 +4,4 @@
Encryption is a process of converting plain text data into a cipher text that can only be deciphered by someone who has the decryption key. This makes it difficult for attackers to access sensitive data, even if they are able to intercept it or gain unauthorized access to it. Encryption is a process of converting plain text data into a cipher text that can only be deciphered by someone who has the decryption key. This makes it difficult for attackers to access sensitive data, even if they are able to intercept it or gain unauthorized access to it.
To encrypt sensitive data, you can use encryption algorithms such as `AES` or `RSA`, along with a strong key management system to ensure that keys are securely stored and managed. Additionally, you can implement other security measures such as access controls, firewalls, and intrusion detection systems to further protect sensitive data. To encrypt sensitive data, you can use encryption algorithms such as `AES` or `RSA`, along with a strong key management system to ensure that keys are securely stored and managed. Additionally, you can implement other security measures such as access controls, firewalls, and intrusion detection systems to further protect sensitive data.

@ -2,4 +2,4 @@
> Use alerts for SMS, Slack, Email, Kibana, Cloudwatch, etc. > Use alerts for SMS, Slack, Email, Kibana, Cloudwatch, etc.
Using alerts for various communication channels such as SMS, Slack, Email, Kibana, Cloudwatch, etc. can help you quickly respond to any issues or anomalies in your system. These alerts can be set up to notify you in real-time if a particular event or condition occurs, allowing you to take proactive measures to prevent downtime, data loss, or security breaches. Additionally, alerts can provide valuable insights into system performance and user behavior, allowing you to make informed decisions about your API's design and implementation. Using alerts for various communication channels such as SMS, Slack, Email, Kibana, Cloudwatch, etc. can help you quickly respond to any issues or anomalies in your system. These alerts can be set up to notify you in real-time if a particular event or condition occurs, allowing you to take proactive measures to prevent downtime, data loss, or security breaches. Additionally, alerts can provide valuable insights into system performance and user behavior, allowing you to make informed decisions about your API's design and implementation.

@ -2,6 +2,6 @@
> Limit requests (throttling) to avoid DDoS / Brute Force attacks. > Limit requests (throttling) to avoid DDoS / Brute Force attacks.
Limiting requests through throttling is important to prevent DDoS attacks and brute force attacks. DDoS attacks overwhelm the server with too many requests, while brute force attacks try to guess user credentials through multiple login attempts. Limiting requests through throttling is important to prevent DDoS attacks and brute force attacks. DDoS attacks overwhelm the server with too many requests, while brute force attacks try to guess user credentials through multiple login attempts.
Throttling limits the number of requests that can be sent within a certain time period, making it harder for attackers to carry out these types of attacks. This can protect the system from being overwhelmed and can prevent attackers from gaining unauthorized access. Throttling limits the number of requests that can be sent within a certain time period, making it harder for attackers to carry out these types of attacks. This can protect the system from being overwhelmed and can prevent attackers from gaining unauthorized access.

@ -2,4 +2,4 @@
> Token expiry should be set to a reasonable time to reduce the window of vulnerability, limit the impact of token theft, and improve overall security. > Token expiry should be set to a reasonable time to reduce the window of vulnerability, limit the impact of token theft, and improve overall security.
Setting a short token expiration time (TTL, RTTL) is important for security purposes, as it reduces the window of vulnerability, limits the impact of token theft, and improves overall security. However, the expiration time should be balanced with usability, as setting it too short may inconvenience users and reduce productivity. Setting a short token expiration time (TTL, RTTL) is important for security purposes, as it reduces the window of vulnerability, limits the impact of token theft, and improves overall security. However, the expiration time should be balanced with usability, as setting it too short may inconvenience users and reduce productivity.

@ -2,4 +2,4 @@
> Audit your design and implementation with unit/integration tests coverage. > Audit your design and implementation with unit/integration tests coverage.
Unit and integration testing can help identify vulnerabilities in the API code and design, such as input validation errors, authentication and authorization flaws, and other security-related issues. By performing comprehensive testing, developers can ensure that the API works as intended and that it is secure against common attacks such as injection attacks, cross-site scripting, and other exploits. Adequate testing can also help identify and resolve performance bottlenecks, improve scalability and reliability, and ensure the overall quality of the API. Unit and integration testing can help identify vulnerabilities in the API code and design, such as input validation errors, authentication and authorization flaws, and other security-related issues. By performing comprehensive testing, developers can ensure that the API works as intended and that it is secure against common attacks such as injection attacks, cross-site scripting, and other exploits. Adequate testing can also help identify and resolve performance bottlenecks, improve scalability and reliability, and ensure the overall quality of the API.

@ -5,4 +5,3 @@
Ensure that your API server uses HTTPS instead of HTTP. HTTPS is a secure protocol that encrypts data in transit, making it difficult for attackers to intercept and read sensitive information. To implement HTTPS, you need to obtain an SSL/TLS certificate and configure your server to use HTTPS. Ensure that your API server uses HTTPS instead of HTTP. HTTPS is a secure protocol that encrypts data in transit, making it difficult for attackers to intercept and read sensitive information. To implement HTTPS, you need to obtain an SSL/TLS certificate and configure your server to use HTTPS.
HTTPS uses ciphers to encrypt data in transit. It is important to choose secure ciphers that are resistant to attacks and offer strong encryption. Some common secure ciphers include AES, ChaCha20, and ECDHE for key exchange. Make sure to disable weak and outdated ciphers, such as RC4 and TLS 1.0/1.1, which are vulnerable to attacks. HTTPS uses ciphers to encrypt data in transit. It is important to choose secure ciphers that are resistant to attacks and offer strong encryption. Some common secure ciphers include AES, ChaCha20, and ECDHE for key exchange. Make sure to disable weak and outdated ciphers, such as RC4 and TLS 1.0/1.1, which are vulnerable to attacks.

@ -2,4 +2,4 @@
> Use IDS and/or IPS systems to detect and block attacks. > Use IDS and/or IPS systems to detect and block attacks.
Intrusion detection systems (IDS) and intrusion prevention systems (IPS) can be used to detect and block attacks. These systems can be configured to monitor all incoming and outgoing traffic, and detect any suspicious activity. If any suspicious activity is detected, the systems can be configured to block the traffic, preventing the attack from succeeding. IDS and IPS systems can be implemented using various tools and technologies such as network intrusion detection systems (NIDS), host-based intrusion detection systems (HIDS), and network intrusion prevention systems (NIPS). These systems can be deployed alongside the API, and configured to monitor all incoming and outgoing traffic. The systems can be configured to provide real-time alerts to security teams if any suspicious activity is detected, allowing for immediate action to be taken. Intrusion detection systems (IDS) and intrusion prevention systems (IPS) can be used to detect and block attacks. These systems can be configured to monitor all incoming and outgoing traffic, and detect any suspicious activity. If any suspicious activity is detected, the systems can be configured to block the traffic, preventing the attack from succeeding. IDS and IPS systems can be implemented using various tools and technologies such as network intrusion detection systems (NIDS), host-based intrusion detection systems (HIDS), and network intrusion prevention systems (NIPS). These systems can be deployed alongside the API, and configured to monitor all incoming and outgoing traffic. The systems can be configured to provide real-time alerts to security teams if any suspicious activity is detected, allowing for immediate action to be taken.

@ -14,4 +14,4 @@ There are several reasons why basic authentication should be avoided and replace
- No support for multi-factor authentication: Basic authentication does not support multi-factor authentication (MFA), which is a critical security feature that provides an additional layer of protection against unauthorized access. - No support for multi-factor authentication: Basic authentication does not support multi-factor authentication (MFA), which is a critical security feature that provides an additional layer of protection against unauthorized access.
In contrast, other authentication techniques such as OAuth, OpenID Connect, and SAML provide more secure and robust methods for authentication. These methods typically use encrypted protocols to protect the user's credentials, provide mechanisms for verifying the integrity of the data, and support MFA. As a result, they are much more secure and reliable than basic authentication and should be used whenever possible. In contrast, other authentication techniques such as OAuth, OpenID Connect, and SAML provide more secure and robust methods for authentication. These methods typically use encrypted protocols to protect the user's credentials, provide mechanisms for verifying the integrity of the data, and support MFA. As a result, they are much more secure and reliable than basic authentication and should be used whenever possible.

@ -3,4 +3,3 @@
> Validate `content-type` on request headers to prevent XSS attacks > Validate `content-type` on request headers to prevent XSS attacks
Validating the `Content-Type` header on the request can help to make APIs more secure by ensuring that the request data is in the expected format and reducing the risk of attacks such as injection attacks or cross-site scripting (XSS). Validating the `Content-Type` header on the request can help to make APIs more secure by ensuring that the request data is in the expected format and reducing the risk of attacks such as injection attacks or cross-site scripting (XSS).

@ -2,4 +2,4 @@
> Validate user input to avoid common vulnerabilities > Validate user input to avoid common vulnerabilities
User input is a common source of vulnerabilities in web applications. This is because user input is often not properly validated, sanitized, or escaped before being used in a web application. This can allow an attacker to manipulate the input and execute malicious code or cause the application to behave unexpectedly. User input is a common source of vulnerabilities in web applications. This is because user input is often not properly validated, sanitized, or escaped before being used in a web application. This can allow an attacker to manipulate the input and execute malicious code or cause the application to behave unexpectedly.

@ -2,4 +2,4 @@
> Send `X-Frame-Options: deny` header. > Send `X-Frame-Options: deny` header.
The `X-Frame-Options` header prevents the page from being displayed in an iframe, which is commonly used in clickjacking attacks. By setting the value of this header to `deny`, you are telling the browser not to display the page in any iframe. This helps prevent the page from being embedded within an attacker's website and reduces the risk of clickjacking attacks. The `X-Frame-Options` header prevents the page from being displayed in an iframe, which is commonly used in clickjacking attacks. By setting the value of this header to `deny`, you are telling the browser not to display the page in any iframe. This helps prevent the page from being embedded within an attacker's website and reduces the risk of clickjacking attacks.

@ -2,4 +2,4 @@
> Get your alerts to become notifications. > Get your alerts to become notifications.
If you've set everyting up correctly, your health checks should automatically destroy bad instances and spawn new ones. There's usually no action to take when getting a CloudWatch alert, as everything should be automated. If you're getting alerts where manual intervention is required, do a post-mortem and figure out if there's a way you can automate the action in future. The last time I had an actionable alert from CloudWatch was about a year ago, and it's extremely awesome not to be woken up at 4am for ops alerts any more. If you've set everyting up correctly, your health checks should automatically destroy bad instances and spawn new ones. There's usually no action to take when getting a CloudWatch alert, as everything should be automated. If you're getting alerts where manual intervention is required, do a post-mortem and figure out if there's a way you can automate the action in future. The last time I had an actionable alert from CloudWatch was about a year ago, and it's extremely awesome not to be woken up at 4am for ops alerts any more.

@ -1,3 +1,3 @@
# App Changes for AWS # App Changes for AWS
While a lot of applications can probably just be deployed to an EC2 instance and work well, if you're coming from a physical environment, you may need to re-architect your application in order to accomodate changes. Don't just think you can copy the files over and be done with it. While a lot of applications can probably just be deployed to an EC2 instance and work well, if you're coming from a physical environment, you may need to re-architect your application in order to accomodate changes. Don't just think you can copy the files over and be done with it.

@ -1,3 +1,3 @@
# Automate Everything # Automate Everything
This is more of general operations advice than AWS specific, but everything needs to be automated. Recovery, deployment, failover, etc. Package and OS updates should be managed by something, whether it's just a bash script, or Chef/Puppet, etc. You shouldn't have to care about this stuff. As mentioned in a different tip, you should also make sure to disable SSH access, as this will pretty quickly highlight any part of your process that isn't automated. Remember the key phrase from the earlier tip, if you have to SSH into your servers, then your automation has failed. This is more of general operations advice than AWS specific, but everything needs to be automated. Recovery, deployment, failover, etc. Package and OS updates should be managed by something, whether it's just a bash script, or Chef/Puppet, etc. You shouldn't have to care about this stuff. As mentioned in a different tip, you should also make sure to disable SSH access, as this will pretty quickly highlight any part of your process that isn't automated. Remember the key phrase from the earlier tip, if you have to SSH into your servers, then your automation has failed.

@ -2,4 +2,4 @@
> Avoid filesystem mounts (FUSE, etc). > Avoid filesystem mounts (FUSE, etc).
I've found them to be about as reliable as a large government department when used in critical applications. Use the SDK instead. I've found them to be about as reliable as a large government department when used in critical applications. Use the SDK instead.

@ -2,4 +2,4 @@
> Don't use multiple scaling triggers on the same group. > Don't use multiple scaling triggers on the same group.
If you have multiple CloudWatch alarms which trigger scaling actions for the same auto-scaling group, it might not work as you initially expect it to. For example, let's say you add a trigger to scale up when CPU usage gets too high, or when the inbound network traffic gets high, and your scale down actions are the opposite. You might get an increase in CPU usage, but your inbound network is fine. So the high CPU trigger causes a scale-up action, but the low inbound traffic alarm immediately triggers a scale-down action. Depending on how you've set your cooldown period, this can cause quite a problem as they'll just fight against each other. If you want multiple triggers, you can use multiple auto-scaling groups. If you have multiple CloudWatch alarms which trigger scaling actions for the same auto-scaling group, it might not work as you initially expect it to. For example, let's say you add a trigger to scale up when CPU usage gets too high, or when the inbound network traffic gets high, and your scale down actions are the opposite. You might get an increase in CPU usage, but your inbound network is fine. So the high CPU trigger causes a scale-up action, but the low inbound traffic alarm immediately triggers a scale-down action. Depending on how you've set your cooldown period, this can cause quite a problem as they'll just fight against each other. If you want multiple triggers, you can use multiple auto-scaling groups.

@ -2,4 +2,4 @@
> Don't give servers static/elastic IPs. > Don't give servers static/elastic IPs.
For a typical web application, you should put things behind a load balancer, and balance them between AZs. There are a few cases where Elastic IPs will probably need to be used, but in order to make best use of auto-scaling you'll want to use a load balancer instad of giving every instance their own unique IP. For a typical web application, you should put things behind a load balancer, and balance them between AZs. There are a few cases where Elastic IPs will probably need to be used, but in order to make best use of auto-scaling you'll want to use a load balancer instad of giving every instance their own unique IP.

@ -2,4 +2,4 @@
> Make sure AWS is right for your workload. > Make sure AWS is right for your workload.
You should make sure that using AWS is correct for your particular workload. If you have a steady load and 24/7 servers, it's possible there are cheaper providers you can use, or it might even be cheaper to use dedicated hardware of your own. One of the big benefits of AWS is the ability to scale up and down rapidly in response to load, but not everyone needs that feature. As when purchasing anything, you should shop around a bit first to make sure you're getting the best deal for what you need You should make sure that using AWS is correct for your particular workload. If you have a steady load and 24/7 servers, it's possible there are cheaper providers you can use, or it might even be cheaper to use dedicated hardware of your own. One of the big benefits of AWS is the ability to scale up and down rapidly in response to load, but not everyone needs that feature. As when purchasing anything, you should shop around a bit first to make sure you're getting the best deal for what you need

@ -2,4 +2,4 @@
> Be aware of AWS service limits before you deploy. > Be aware of AWS service limits before you deploy.
Various service limits are enforced which aren't highlighted until you're actually trying to deploy your application and get the error notification. These limits can easily be increased by making a request to AWS support, however that can involve a significant turn around time (as low as a few minutes, up to a few days, based on past experience), during which you won't be able to finish deploying. A few days before deploying, you should consult the service limits page to see if you think you're going to exceed any of them, and make your support request ahead of time. You will need to make a separate request to each department where you need a limit increased. It's also worth pointing out that some limits are global, while others are per-region. Various service limits are enforced which aren't highlighted until you're actually trying to deploy your application and get the error notification. These limits can easily be increased by making a request to AWS support, however that can involve a significant turn around time (as low as a few minutes, up to a few days, based on past experience), during which you won't be able to finish deploying. A few days before deploying, you should consult the service limits page to see if you think you're going to exceed any of them, and make your support request ahead of time. You will need to make a separate request to each department where you need a limit increased. It's also worth pointing out that some limits are global, while others are per-region.

@ -2,4 +2,4 @@
> Set up granular billing alerts. > Set up granular billing alerts.
You should always have at least one billing alert set up, but that will only tell you on a monthly basis once you've exceeded your allowance. If you want to catch runaway billing early, you need a more fine grained approach. The way I do it is to set up an alert for my expected usage each week. So the first week's alert for say $1,000, the second for $2,000, third for $3,000, etc. If the week-2 alarm goes off before the 14th/15th of the month, then I know something is probably going wrong. For even more fine-grained control, you can set this up for each individual service, that way you instantly know which service is causing the problem. This could be useful if your usage on one service is quite steady month-to-month, but another is more erratic. Have the indidividual weekly alerts for the steady one, but just an overall one for the more erratic one. If everything is steady, then this is probably overkill, as looking at CloudWatch will quickly tell you which service is the one causing the problem. You should always have at least one billing alert set up, but that will only tell you on a monthly basis once you've exceeded your allowance. If you want to catch runaway billing early, you need a more fine grained approach. The way I do it is to set up an alert for my expected usage each week. So the first week's alert for say $1,000, the second for $2,000, third for $3,000, etc. If the week-2 alarm goes off before the 14th/15th of the month, then I know something is probably going wrong. For even more fine-grained control, you can set this up for each individual service, that way you instantly know which service is causing the problem. This could be useful if your usage on one service is quite steady month-to-month, but another is more erratic. Have the indidividual weekly alerts for the steady one, but just an overall one for the more erratic one. If everything is steady, then this is probably overkill, as looking at CloudWatch will quickly tell you which service is the one causing the problem.

@ -2,4 +2,4 @@
> Use "-" instead of "." in bucket names for SSL. > Use "-" instead of "." in bucket names for SSL.
If you ever want to use your bucket over SSL, using a "." will cause you to get certificate mismatch errors. You can't change bucket names once you've created them, so you'd have to copy everything to a new bucket. If you ever want to use your bucket over SSL, using a "." will cause you to get certificate mismatch errors. You can't change bucket names once you've created them, so you'd have to copy everything to a new bucket.

@ -2,4 +2,4 @@
> Use CloudTrail to keep an audit log. > Use CloudTrail to keep an audit log.
CloudTrail will log any action performed via the APIs or web console into an S3 bucket. Set up the bucket with versioning to be sure no one can modify your logs, and you then have a complete audit trail of all changes in your account. You hope that you will never need to use this, but it's well worth having for when you do. CloudTrail will log any action performed via the APIs or web console into an S3 bucket. Set up the bucket with versioning to be sure no one can modify your logs, and you then have a complete audit trail of all changes in your account. You hope that you will never need to use this, but it's well worth having for when you do.

@ -2,4 +2,4 @@
> Use the CLI tools. > Use the CLI tools.
It can become extremely tedious to create alarms using the web console, especially if you're setting up a lot of similar alarms, as there's no ability to "clone" an existing alarm while making a minor change elsewhere. Scripting this using the CLI tools can save you lots of time. It can become extremely tedious to create alarms using the web console, especially if you're setting up a lot of similar alarms, as there's no ability to "clone" an existing alarm while making a minor change elsewhere. Scripting this using the CLI tools can save you lots of time.

@ -2,4 +2,4 @@
> Use detailed monitoring. > Use detailed monitoring.
It's ~$3.50 per instance/month, and well worth the extra cost for the extra detail. 1 minute granularity is much better than 5 minute. You can have cases where a problem is hidden in the 5 minute breakdown, but shows itself quite clearly in the 1 minute graphs. This may not be useful for everyone, but it's made investigating some issues much easier for me. It's ~$3.50 per instance/month, and well worth the extra cost for the extra detail. 1 minute granularity is much better than 5 minute. You can have cases where a problem is hidden in the 5 minute breakdown, but shows itself quite clearly in the 1 minute graphs. This may not be useful for everyone, but it's made investigating some issues much easier for me.

@ -2,4 +2,4 @@
> Use the free metrics. > Use the free metrics.
CloudWatch monitors all sorts of things for free (bandwidth, CPU usage, etc.), and you get up to 2 weeks of historical data. This saves you having to use your own tools to monitor you systems. If you need longer than 2 weeks, unfortunately you'll need to use a third-party or custom built monitoring solution. CloudWatch monitors all sorts of things for free (bandwidth, CPU usage, etc.), and you get up to 2 weeks of historical data. This saves you having to use your own tools to monitor you systems. If you need longer than 2 weeks, unfortunately you'll need to use a third-party or custom built monitoring solution.

@ -2,4 +2,4 @@
> Only use the availability zones (AZs) your ELB is configured for. > Only use the availability zones (AZs) your ELB is configured for.
If you add your scaling group to multiple AZs, make sure your ELB is configured to use all of those AZs, otherwise your capacity will scale up, and the load balancer won't be able to see them. If you add your scaling group to multiple AZs, make sure your ELB is configured to use all of those AZs, otherwise your capacity will scale up, and the load balancer won't be able to see them.

@ -4,4 +4,4 @@
This sounds crazy, I know, but port 22 should be disallowed for everyone in your security group. If there's one thing you take away from this post, this should be it: **If you have to SSH into your servers, then your automation has failed**. Disabling it at the firewall level (rather than on the servers themselves) will help the transition to this frame of thinking, as it will highlight any areas you need to automate, while still letting you easily re-instate access to solve immediate issues. It's incredibly freeing to know that you never need to SSH into an instance. This is both the most frightening and yet most useful thing I've learned. This sounds crazy, I know, but port 22 should be disallowed for everyone in your security group. If there's one thing you take away from this post, this should be it: **If you have to SSH into your servers, then your automation has failed**. Disabling it at the firewall level (rather than on the servers themselves) will help the transition to this frame of thinking, as it will highlight any areas you need to automate, while still letting you easily re-instate access to solve immediate issues. It's incredibly freeing to know that you never need to SSH into an instance. This is both the most frightening and yet most useful thing I've learned.
Disabling inbound SSH has just been a way for me to stop myself cheating with automation (Oh, I'll just SSH in and fix this one thing). I can still re-enable it in the security group if I need to actively debug something on an instance, since sometimes there really is no other way to debug certain issues. It also depends on your application; If your application relies on you being able to push things to a server via SSH, then disabling it might be a bad idea. Blocking inbound SSH worked for me, and forced me to get my automation into a decent state, but it might not be for everyone. Disabling inbound SSH has just been a way for me to stop myself cheating with automation (Oh, I'll just SSH in and fix this one thing). I can still re-enable it in the security group if I need to actively debug something on an instance, since sometimes there really is no other way to debug certain issues. It also depends on your application; If your application relies on you being able to push things to a server via SSH, then disabling it might be a bad idea. Blocking inbound SSH worked for me, and forced me to get my automation into a decent state, but it might not be for everyone.

@ -2,4 +2,4 @@
> Use EC2 roles, do not give applications an IAM account. > Use EC2 roles, do not give applications an IAM account.
If your application has AWS credentials baked into it, you're "doing it wrong". One of the reasons it's important to use the AWS SDK for your language is that you can really easily use EC2 IAM roles. The idea of a role is that you specify the permissions a certain role should get, then assign that role to an EC2 instance. Whenever you use the AWS SDK on that instance, you don't specify any credentials. Instead, the SDK will retrieve temporary credentials which have the permissions of the role you set up. This is all handled transparently as far as you're concerned. It's secure, and extremely useful. If your application has AWS credentials baked into it, you're "doing it wrong". One of the reasons it's important to use the AWS SDK for your language is that you can really easily use EC2 IAM roles. The idea of a role is that you specify the permissions a certain role should get, then assign that role to an EC2 instance. Whenever you use the AWS SDK on that instance, you don't specify any credentials. Instead, the SDK will retrieve temporary credentials which have the permissions of the role you set up. This is all handled transparently as far as you're concerned. It's secure, and extremely useful.

@ -2,4 +2,4 @@
> Set up event subscriptions for failover. > Set up event subscriptions for failover.
If you're using a Multi-AZ setup, this is one of those things you might not think about which ends up being incredibly useful when you do need it. If you're using a Multi-AZ setup, this is one of those things you might not think about which ends up being incredibly useful when you do need it.

@ -2,4 +2,4 @@
> Assign permissions to groups, not users. > Assign permissions to groups, not users.
Managing users can be a pain, if you're using Active Directory, or some other external authentication mechanism which you've integrated with IAM, then this probably won't matter as much (or maybe it matters more). But I've found it much easier to manage permissions by assigning them only to groups, rather than to individual users. It's much easier to rein in permissions and get an overall view of the system than going through each individual user to see what permissions have been assigned. Managing users can be a pain, if you're using Active Directory, or some other external authentication mechanism which you've integrated with IAM, then this probably won't matter as much (or maybe it matters more). But I've found it much easier to manage permissions by assigning them only to groups, rather than to individual users. It's much easier to rein in permissions and get an overall view of the system than going through each individual user to see what permissions have been assigned.

@ -2,4 +2,4 @@
> Decide on a key-management strategy from the start. > Decide on a key-management strategy from the start.
Are you going to have one key-pair per group of instances, or are you going to have one key-pair you use for your entire account? It's easy to modify your authorized-keys file with a bootstrap script of course, but you need to decide if you want to manage multiple key-pairs or not, as things will get complicated later on if you try to change your mind. Are you going to have one key-pair per group of instances, or are you going to have one key-pair you use for your entire account? It's easy to modify your authorized-keys file with a bootstrap script of course, but you need to decide if you want to manage multiple key-pairs or not, as things will get complicated later on if you try to change your mind.

@ -2,4 +2,4 @@
> IAM users can have multi-factor authentication, use it! > IAM users can have multi-factor authentication, use it!
Enable MFA for your IAM users to add an extra layer of security. Your master account should most definitely have this, but it's also worth enabling it for normal IAM users too. Enable MFA for your IAM users to add an extra layer of security. Your master account should most definitely have this, but it's also worth enabling it for normal IAM users too.

@ -2,5 +2,4 @@
> Pre-warm your ELBs if you're expecting heavy traffic. > Pre-warm your ELBs if you're expecting heavy traffic.
It takes time for your ELB to scale up capacity. If you know you're going to have a large traffic spike (selling tickets, big event, etc), you need to "warm up" your ELB in advance. You can inject a load of traffic, and it will cause ELB to scale up and not choke when you actually get the traffic, however AWS suggest you contact them instead to prewarm your load balancer. (Source: [Best Practices in Evaluating Elastic Load Balancing](https://aws.amazon.com/articles/best-practices-in-evaluating-elastic-load-balancing/#pre-warming)). Alternatively you can install your own load balancer software on an EC2 instance and use that instead (HAProxy, etc). It takes time for your ELB to scale up capacity. If you know you're going to have a large traffic spike (selling tickets, big event, etc), you need to "warm up" your ELB in advance. You can inject a load of traffic, and it will cause ELB to scale up and not choke when you actually get the traffic, however AWS suggest you contact them instead to prewarm your load balancer. (Source: [Best Practices in Evaluating Elastic Load Balancing](https://aws.amazon.com/articles/best-practices-in-evaluating-elastic-load-balancing/#pre-warming)). Alternatively you can install your own load balancer software on an EC2 instance and use that instead (HAProxy, etc).

@ -2,4 +2,4 @@
> Always be redundant across availability zones (AZs). > Always be redundant across availability zones (AZs).
AZs can have outages, it's happened in the past that certain things in an AZ have gone down. Spreading your application into multiple AZs is as simple as adding a new AZ to your load balancer and starting an instance in that AZ. You should spread your load over two AZs at the very least! If you can afford it, being redundant across regions can also be well worth it, but this generally has a more complex set up cost and isn't always necessary. You can now copy AMIs between regions, and you can set up your Route53 records to balance traffic between regions, but you can't use a single ELB across regions. AZs can have outages, it's happened in the past that certain things in an AZ have gone down. Spreading your application into multiple AZs is as simple as adding a new AZ to your load balancer and starting an instance in that AZ. You should spread your load over two AZs at the very least! If you can afford it, being redundant across regions can also be well worth it, but this generally has a more complex set up cost and isn't always necessary. You can now copy AMIs between regions, and you can set up your Route53 records to balance traffic between regions, but you can't use a single ELB across regions.

@ -2,4 +2,4 @@
> Don't keep unassociated Elastic IPs. > Don't keep unassociated Elastic IPs.
You get charged for any Elastic IPs you have created but not associated with an instance, so make sure you don't keep them around once you're done with them. You get charged for any Elastic IPs you have created but not associated with an instance, so make sure you don't keep them around once you're done with them.

@ -2,4 +2,4 @@
> Use reserved instances to save big $$$. > Use reserved instances to save big $$$.
Reserving an instance is just putting some money upfront in order to get a lower hourly rate. It ends up being a lot cheaper than an on-demand instance would cost. So if you know you're going to be keeping an instance around for 1 or 3 years, it's well worth reserving them. Reserved instances are a purely logical concept in AWS, you don't assign a specific instance to be reserved, but rather just specify the type and size, and any instances that match the criteria will get the lower price. Reserving an instance is just putting some money upfront in order to get a lower hourly rate. It ends up being a lot cheaper than an on-demand instance would cost. So if you know you're going to be keeping an instance around for 1 or 3 years, it's well worth reserving them. Reserved instances are a purely logical concept in AWS, you don't assign a specific instance to be reserved, but rather just specify the type and size, and any instances that match the criteria will get the lower price.

@ -2,4 +2,4 @@
> Specify a directory on S3 for Hive results. > Specify a directory on S3 for Hive results.
If you use Hive to output results to S3, you must specify a directory in the bucket, not the root of the bucket, otherwise you'll get a rather unhelpful NullPointerException with no real explanation as to why. If you use Hive to output results to S3, you must specify a directory in the bucket, not the root of the bucket, otherwise you'll get a rather unhelpful NullPointerException with no real explanation as to why.

@ -2,4 +2,4 @@
> Scale down on INSUFFICIENT_DATA as well as ALARM. > Scale down on INSUFFICIENT_DATA as well as ALARM.
For your scale-down action, make sure to trigger a scale-down event when there's no metric data, as well as when your trigger goes off. For example, if you have an app which usually has very low traffic, but experiences occasional spikes, you want to be sure that it scales down once the spike is over and the traffic stops. If there's no traffic, you'll get `INSUFFIFIENT_DATA` instead of `ALARM` for your low traffic threshold and it won't trigger a scale-down action. For your scale-down action, make sure to trigger a scale-down event when there's no metric data, as well as when your trigger goes off. For example, if you have an app which usually has very low traffic, but experiences occasional spikes, you want to be sure that it scales down once the spike is over and the traffic stops. If there's no traffic, you'll get `INSUFFIFIENT_DATA` instead of `ALARM` for your low traffic threshold and it won't trigger a scale-down action.

@ -1,3 +1,3 @@
# Scale Horizontally # Scale Horizontally
I've found that using lots of smaller machines is generally more reliable than using a smaller number of larger machines. You need to balance this though, as trying to run your application from 100 t1.micro instances probably isn't going to work very well. Breaking your application into lots of smaller instances means you'll be more resiliant to failure in one of the machines. If you're just running from two massive compute cluster machines, and one goes down, things are going to get bad. I've found that using lots of smaller machines is generally more reliable than using a smaller number of larger machines. You need to balance this though, as trying to run your application from 100 t1.micro instances probably isn't going to work very well. Breaking your application into lots of smaller instances means you'll be more resiliant to failure in one of the machines. If you're just running from two massive compute cluster machines, and one goes down, things are going to get bad.

@ -3,5 +3,3 @@
> Set up automated security auditing. > Set up automated security auditing.
It's important to keep track of changes in your infrastructure's security settings. One way to do this is to first set up a security auditer role ([JSON template](https://gist.github.com/bigsnarfdude/d0758b4fd335085623be)), which will give anyone assigned that role read-only access to any security related settings on your account. You can then use this rather [fantastic Python script](https://gist.github.com/jlevy/cce1b44fc24f94599d0a4b3e613cc15d), which will go over all the items in your account and produce a canonical output showing your configuration. You set up a cronjob somewhere to run this script, and compare its output to the output from the previous run. Any differences will show you exactly what has been changed in your security configuration. It's useful to set this up and just have it email you the diff of any changes. (Source: Intrusion Detection in the Cloud - [Presentation](http://awsmedia.s3.amazonaws.com/SEC402.pdf)) It's important to keep track of changes in your infrastructure's security settings. One way to do this is to first set up a security auditer role ([JSON template](https://gist.github.com/bigsnarfdude/d0758b4fd335085623be)), which will give anyone assigned that role read-only access to any security related settings on your account. You can then use this rather [fantastic Python script](https://gist.github.com/jlevy/cce1b44fc24f94599d0a4b3e613cc15d), which will go over all the items in your account and produce a canonical output showing your configuration. You set up a cronjob somewhere to run this script, and compare its output to the output from the previous run. Any differences will show you exactly what has been changed in your security configuration. It's useful to set this up and just have it email you the diff of any changes. (Source: Intrusion Detection in the Cloud - [Presentation](http://awsmedia.s3.amazonaws.com/SEC402.pdf))

@ -1,3 +1,3 @@
# Tag Everything # Tag Everything
Pretty much everything can be given tags, use them! They're great for organising things, make it easier to search and group things up. You can also use them to trigger certain behaviour on your instances, for example a tag of env=debug could put your application into debug mode when it deploys, etc. Pretty much everything can be given tags, use them! They're great for organising things, make it easier to search and group things up. You can also use them to trigger certain behaviour on your instances, for example a tag of env=debug could put your application into debug mode when it deploys, etc.

@ -2,4 +2,4 @@
> Terminate SSL on the load balancer. > Terminate SSL on the load balancer.
You'll need to add your SSL certificate information to the ELB, but this will take the overhead of SSL termination away from your servers which can speed things up. Additionally, if you upload your SSL certificate, you can pass through the HTTPS traffic and the load balancer will add some extra headers to your request (x-forwarded-for, etc), which are useful if you want to know who the end user is. If you just forward TCP, then those headers aren't added and you lose the information. You'll need to add your SSL certificate information to the ELB, but this will take the overhead of SSL termination away from your servers which can speed things up. Additionally, if you upload your SSL certificate, you can pass through the HTTPS traffic and the load balancer will add some extra headers to your request (x-forwarded-for, etc), which are useful if you want to know who the end user is. If you just forward TCP, then those headers aren't added and you lose the information.

@ -2,4 +2,4 @@
> Use termination protection for non-auto-scaling instances. > Use termination protection for non-auto-scaling instances.
If you have any instances which are one-off things that aren't under auto-scaling, then you should probably enable termination protection, to stop anyone from accidentally deleting the instance. I've had it happen, it sucks, learn from my mistake! If you have any instances which are one-off things that aren't under auto-scaling, then you should probably enable termination protection, to stop anyone from accidentally deleting the instance. I've had it happen, it sucks, learn from my mistake!

@ -2,4 +2,4 @@
> Have tools to view application logs. > Have tools to view application logs.
You should have an admin tool, syslog viewer, or something that allows you to view current real-time log info without needing to SSH into a running instance. If you have centralised logging (which you really should), then you just want to be sure you can read the logs there without needing to use SSH. Needing to SSH into a running application instance to view logs is going to become problematic. You should have an admin tool, syslog viewer, or something that allows you to view current real-time log info without needing to SSH into a running instance. If you have centralised logging (which you really should), then you just want to be sure you can read the logs there without needing to use SSH. Needing to SSH into a running application instance to view logs is going to become problematic.

@ -2,4 +2,4 @@
> Use ALIAS records. > Use ALIAS records.
An ALIAS record will link your record set to a particular AWS resource directly (i.e. you can map a domain to an S3 bucket), but the key is that you don't get charged for any ALIAS lookups. So whereas a CNAME entry would cost you money, an ALIAS record won't. Also, unlike a CNAME, you can use an ALIAS on your zone apex. You can read more about this on [the AWS page for creating alias resource record sets](http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingAliasRRSets.html). An ALIAS record will link your record set to a particular AWS resource directly (i.e. you can map a domain to an S3 bucket), but the key is that you don't get charged for any ALIAS lookups. So whereas a CNAME entry would cost you money, an ALIAS record won't. Also, unlike a CNAME, you can use an ALIAS on your zone apex. You can read more about this on [the AWS page for creating alias resource record sets](http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/CreatingAliasRRSets.html).

@ -5,4 +5,3 @@
Usually you'll have an "operations account" for a service, and your entire ops team will have the password. With AWS, you definitely don't want to do that. Everyone gets an IAM user with just the permissions they need (least privilege). An IAM user can control everything in the infrastructure. At the time of writing, the only thing an IAM user can't access are some parts of the billing pages. Usually you'll have an "operations account" for a service, and your entire ops team will have the password. With AWS, you definitely don't want to do that. Everyone gets an IAM user with just the permissions they need (least privilege). An IAM user can control everything in the infrastructure. At the time of writing, the only thing an IAM user can't access are some parts of the billing pages.
If you want to protect your account even more, make sure to [enable multi-factor authentication](http://aws.amazon.com/iam/details/mfa/) for everyone (you can use Google Authenticator). I've heard of some users who give the MFA token to two people, and the password to two others, so to perform any action on the master account, two of the users need to agree. This is overkill for my case, but worth mentioning in case someone else wants to do it. If you want to protect your account even more, make sure to [enable multi-factor authentication](http://aws.amazon.com/iam/details/mfa/) for everyone (you can use Google Authenticator). I've heard of some users who give the MFA token to two people, and the password to two others, so to perform any action on the master account, two of the users need to agree. This is overkill for my case, but worth mentioning in case someone else wants to do it.

@ -1,3 +1,3 @@
# Use IAM Roles # Use IAM Roles
Don't create users for application, always use IAM roles if you can. They simplify everything, and keeps things secure. Having application users just creates a point of failure (what if someone accidentally deletes the API key?) and it becomes a pain to manage. Don't create users for application, always use IAM roles if you can. They simplify everything, and keeps things secure. Having application users just creates a point of failure (what if someone accidentally deletes the API key?) and it becomes a pain to manage.

@ -9,4 +9,4 @@ Your CSS should be organized, using a CSS preprocessor can help you with that. S
- [TestMyCSS | Optimize and Check CSS Performance](http://www.testmycss.com/) - [TestMyCSS | Optimize and Check CSS Performance](http://www.testmycss.com/)
- [CSS Stats](https://cssstats.com/) - [CSS Stats](https://cssstats.com/)
- [macbre/analyze-css: CSS selectors complexity and performance analyzer](https://github.com/macbre/analyze-css) - [macbre/analyze-css: CSS selectors complexity and performance analyzer](https://github.com/macbre/analyze-css)
- [Project Wallace](https://www.projectwallace.com/) is like CSS Stats but stores stats over time so you can track your changes - [Project Wallace](https://www.projectwallace.com/) is like CSS Stats but stores stats over time so you can track your changes

@ -10,4 +10,4 @@ Use the Timeline tool in the Chrome Developer Tool to evaluate scripts events an
- [JavaScript Profiling With The Chrome Developer Tools](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/) - [JavaScript Profiling With The Chrome Developer Tools](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
- [How to Record Heap Snapshots | Tools for Web Developers](https://developers.google.com/web/tools/chrome-devtools/memory-problems/heap-snapshots) - [How to Record Heap Snapshots | Tools for Web Developers](https://developers.google.com/web/tools/chrome-devtools/memory-problems/heap-snapshots)
- [Chapter 22 - Profiling the Frontend - Blackfire](https://blackfire.io/docs/book/22-frontend-profiling) - [Chapter 22 - Profiling the Frontend - Blackfire](https://blackfire.io/docs/book/22-frontend-profiling)
- [30 Tips To Improve Javascript Performance](http://www.monitis.com/blog/30-tips-to-improve-javascript-performance/) - [30 Tips To Improve Javascript Performance](http://www.monitis.com/blog/30-tips-to-improve-javascript-performance/)

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save