// API callback
related_results_labels_thumbs({"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$blogger":"http://schemas.google.com/blogger/2008","xmlns$georss":"http://www.georss.org/georss","xmlns$gd":"http://schemas.google.com/g/2005","xmlns$thr":"http://purl.org/syndication/thread/1.0","id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012"},"updated":{"$t":"2023-10-23T04:18:30.735-07:00"},"category":[{"term":"AWS"},{"term":"AWS Certified Solutions Architect"},{"term":"Architect"},{"term":"Certification"},{"term":"AWS Certified Developer"},{"term":"AWS Certified SysOps Administrator"},{"term":"EC2"},{"term":"Course"},{"term":"Development"},{"term":"Cognito"},{"term":"Tutorial"},{"term":"SysOps Administration"},{"term":"CloudFront"},{"term":"News"},{"term":"S3"},{"term":"AutoScaling"},{"term":"Cordova"},{"term":"DynamoDB"},{"term":"ELB"},{"term":"IAM"},{"term":"Node.JS"},{"term":"PhoneGap"},{"term":"Security"},{"term":"Shared Responsibility"},{"term":"VPC"},{"term":"Amazon Aurora"},{"term":"Android"},{"term":"Denial of Service"},{"term":"EBS"},{"term":"IOS"},{"term":"NodeJS"},{"term":"RDS"},{"term":"AWS IoT"},{"term":"AWS Mobile Hub"},{"term":"Amazon Inspector"},{"term":"Amazon QuickSight"},{"term":"AngularJS"},{"term":"CloudTrail"},{"term":"Cloudformation"},{"term":"Dynamic"},{"term":"ECS"},{"term":"India"},{"term":"Internet of Things"},{"term":"Kinesis Firehose"},{"term":"MEAN"},{"term":"MariaDB"},{"term":"PIOPS"},{"term":"PhantomJS"},{"term":"ReactJS"},{"term":"Region"},{"term":"Route 53"},{"term":"Selenium"},{"term":"Trusted Adviser"},{"term":"WAF"},{"term":"Web Application Firewall"},{"term":"YAML"},{"term":"app"},{"term":"example"}],"title":{"type":"text","$t":"BackSpace Academy Blog"},"subtitle":{"type":"html","$t":"A blog about all things Amazon Web Services (AWS) and Cloud Certification."},"link":[{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/posts\/default"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/-\/AWS?alt=json-in-script\u0026max-results=6"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/search\/label\/AWS"},{"rel":"hub","href":"http://pubsubhubbub.appspot.com/"},{"rel":"next","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/-\/AWS\/-\/AWS?alt=json-in-script\u0026start-index=7\u0026max-results=6"}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"generator":{"version":"7.00","uri":"http://www.blogger.com","$t":"Blogger"},"openSearch$totalResults":{"$t":"40"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"6"},"entry":[{"id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012.post-96012945605615497"},"published":{"$t":"2016-10-03T06:10:00.000-07:00"},"updated":{"$t":"2016-10-05T18:44:02.277-07:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"AngularJS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"CloudFront"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Dynamic"},{"scheme":"http://www.blogger.com/atom/ns#","term":"EC2"},{"scheme":"http://www.blogger.com/atom/ns#","term":"MEAN"},{"scheme":"http://www.blogger.com/atom/ns#","term":"NodeJS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"ReactJS"}],"title":{"type":"text","$t":"Super Fast Dynamic Websites with CloudFront, ReactJS, and NodeJS - Part 1"},"content":{"type":"html","$t":"\u003Cbr \/\u003E\nCloudFront should be an essential component of any web based application deployment. It not only instantly provides super low-latency performance, it also dramatically reduces server costs while providing maximum server uptime.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nCreating low latency static websites with CloudFront is a relatively simple process. You simply upload your site to S3 and create a CloudFront distribution for it. This is great for HTML5 websites and static blogs such as Jeckyl. But what about dynamic sites that need real time information presented to the end user? A different strategy is clearly required. Much has been published about different methods of caching dynamic websites but, I will present the most common sense and reliable technique to achieve this end.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\nServer Side v Browser Side Rendering\u003C\/h3\u003E\nIf you read any book on NodeJS you will no doubt find plenty of examples of rendering Jade templates with Express on the server. If you are still doing this, then you are wasting valuable server resources. A far better option is to render on the browser side. There are a number of frameworks specifically for this, the most popular being Facebook's ReactJS and Google's AngularJS (see \u003Ca href=\"http:\/\/stateofjs.com\/2016\/frontend\/\" target=\"_blank\"\u003EState of JS report\u003C\/a\u003E). I personally use ReactJS and the example will be in ReactJS, but either is fine.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nCreating your site using ReactJS or AngularJS and uploading it to your NodeJS public directory will shift the rendering of your site from your server to the client's browser. Users of your app will no longer be waiting for rendered pages and will see pages appear with the click of a button.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nYou can now create a CloudFront distribution for your ReactJS or AngularJS site.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nAlthough pages may be rendered instantly in the browser, any dynamic data required for the pages will be cached by CloudFront. We most probably do not want our dynamic data cached. We will still need a solution for delivering this data to the browser.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\nHandling Dynamic Data\u003C\/h3\u003E\n\u003Cbr \/\u003E\nAlthough there are many elaborate techniques published for handling dynamic data with CloudFront, the best way is to deliver this data without caching at all from CloudFront.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nNot all HTTP methods are cached by CloudFront, only responses to GET and HEAD requests (although you can also configure CloudFront to cache responses to OPTIONS requests). If we use a different HTTP method, such as POST, PUT or DELETE \u0026nbsp;the request will not be cached by Cloudfront. CloudFront will simply proxy these requests back to our server.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nOur EC2 NodeJS server can now be used to respond to requests for dynamic data by creating an API for our application that responds to POST requests from the client browser.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/2.bp.blogspot.com\/-5Be6dKuaOHQ\/V_JXJqPXlvI\/AAAAAAAAAXA\/xfP1-VLIz9sdkFol9-7ttradYMsWlTCaQCLcB\/s1600\/pptCD4.pptm%2B%255BAutosaved%255D.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" height=\"360\" src=\"https:\/\/2.bp.blogspot.com\/-5Be6dKuaOHQ\/V_JXJqPXlvI\/AAAAAAAAAXA\/xfP1-VLIz9sdkFol9-7ttradYMsWlTCaQCLcB\/s640\/pptCD4.pptm%2B%255BAutosaved%255D.png\" width=\"640\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cdiv style=\"text-align: center;\"\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nSome of you might be wondering why I haven't used serverless technology such as AWS Lambda or API Gateway. Rest assured I will be posting another series using this but, I consider EC2 as the preferred technology for most applications. First of all, costs are rarely mentioned in the serverless discussion. If you have an application that has significant traffic, the conventional EC2\/ELB architecture will be the most cost effective. Secondly, many modern web applications are utilising websocket connections. Connections like this are possible with EC2 directly and also behind an ELB when utilizing proxy protocol. This is not possible with serverless technology as connections are short lived.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nIn the next post in this series we will set up our NodeJS server on EC2, create a CloudFront distribution and, create our API for handling dynamic data.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nBe sure to subscribe to the blog so that you can get the latest updates.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nFor more AWS training and tutorials check out\u0026nbsp;\u003Ca href=\"https:\/\/backspace.academy\/\"\u003Ebackspace.academy\u003C\/a\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ca href=\"https:\/\/backspace.academy\/\" target=\"_blank\"\u003E\u003Cimg src=\"https:\/\/backspace.academy\/assets\/img\/logo.svg\" \/\u003E\u003C\/a\u003E"},"link":[{"rel":"replies","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/96012945605615497\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/10\/super-fast-dynamic-websites-with.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/96012945605615497"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/96012945605615497"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/10\/super-fast-dynamic-websites-with.html","title":"Super Fast Dynamic Websites with CloudFront, ReactJS, and NodeJS - Part 1"}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/2.bp.blogspot.com\/-5Be6dKuaOHQ\/V_JXJqPXlvI\/AAAAAAAAAXA\/xfP1-VLIz9sdkFol9-7ttradYMsWlTCaQCLcB\/s72-c\/pptCD4.pptm%2B%255BAutosaved%255D.png","height":"72","width":"72"},"thr$total":{"$t":"0"}},{"id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012.post-4986015037693333477"},"published":{"$t":"2016-09-29T07:48:00.003-07:00"},"updated":{"$t":"2016-09-29T07:49:55.518-07:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS Certified Developer"},{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS Certified Solutions Architect"},{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS Certified SysOps Administrator"}],"title":{"type":"text","$t":"Attention all exam preppers! AWS Answers"},"content":{"type":"html","$t":"\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/4.bp.blogspot.com\/--9yr3lj5XeU\/V-0pObPzgSI\/AAAAAAAAAWs\/qFj88f-J2xscAU7hQ_0T3Ix5oF48X5hvgCLcB\/s1600\/AWS_Answers.PNG\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/4.bp.blogspot.com\/--9yr3lj5XeU\/V-0pObPzgSI\/AAAAAAAAAWs\/qFj88f-J2xscAU7hQ_0T3Ix5oF48X5hvgCLcB\/s1600\/AWS_Answers.PNG\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cdiv style=\"text-align: center;\"\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nAWS has just released a new \u003Ca href=\"https:\/\/aws.amazon.com\/answers\/\" target=\"_blank\"\u003EAWS Answers\u003C\/a\u003E\u0026nbsp;page that is essential reading for those preparing for the certification exams.\u003Cbr \/\u003E\nIt provides a great overview of AWS architecture considerations."},"link":[{"rel":"replies","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/4986015037693333477\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/09\/attention-all-exam-preppers-aws-answers.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/4986015037693333477"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/4986015037693333477"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/09\/attention-all-exam-preppers-aws-answers.html","title":"Attention all exam preppers! AWS Answers"}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/4.bp.blogspot.com\/--9yr3lj5XeU\/V-0pObPzgSI\/AAAAAAAAAWs\/qFj88f-J2xscAU7hQ_0T3Ix5oF48X5hvgCLcB\/s72-c\/AWS_Answers.PNG","height":"72","width":"72"},"thr$total":{"$t":"0"}},{"id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012.post-5633300852660274272"},"published":{"$t":"2016-09-22T07:43:00.001-07:00"},"updated":{"$t":"2016-09-26T06:28:32.268-07:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Cloudformation"},{"scheme":"http://www.blogger.com/atom/ns#","term":"example"},{"scheme":"http://www.blogger.com/atom/ns#","term":"YAML"}],"title":{"type":"text","$t":"YAML and CloudFormation. Yippee!!!"},"content":{"type":"html","$t":"\u003Ch3 style=\"padding-top: 0px;\"\u003E\n\u003Cspan style=\"color: green; font-size: 16.25px;\"\u003EYAML\u003C\/span\u003E\u003Cspan style=\"color: brown; font-size: 16.25px;\"\u003E:\u003C\/span\u003E\u003Cspan style=\"font-size: 16.25px;\"\u003E \u003C\/span\u003E\u003Cb style=\"font-size: 16.25px;\"\u003EY\u003C\/b\u003E\u003Cspan style=\"font-size: 16.25px;\"\u003EAML \u003C\/span\u003E\u003Cb style=\"font-size: 16.25px;\"\u003EA\u003C\/b\u003E\u003Cspan style=\"font-size: 16.25px;\"\u003Ein't \u003C\/span\u003E\u003Cb style=\"font-size: 16.25px;\"\u003EM\u003C\/b\u003E\u003Cspan style=\"font-size: 16.25px;\"\u003Earkup \u003C\/span\u003E\u003Cb style=\"font-size: 16.25px;\"\u003EL\u003C\/b\u003E\u003Cspan style=\"font-size: 16.25px;\"\u003Eanguage\u003C\/span\u003E\u003C\/h3\u003E\n\u003Cbr \/\u003E\nI spend a heck of a lot of time coding and, like many devops guys, love \u003Ca href=\"http:\/\/coffeescript.org\/\" target=\"_blank\"\u003ECoffeescript\u003C\/a\u003E, \u003Ca href=\"https:\/\/github.com\/pugjs\/pug\" target=\"_blank\"\u003EJade\u003C\/a\u003E, \u003Ca href=\"http:\/\/stylus-lang.com\/\" target=\"_blank\"\u003EStylus \u003C\/a\u003Eand \u003Ca href=\"http:\/\/yaml.org\/\" target=\"_blank\"\u003EYAML\u003C\/a\u003E. No chasing missing semicolons, commas and curly braces. I just write clean code how it should be and, at least twice as fast.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nJSON, like plain javascript, is a lot cleaner, quicker and easier to read when you remove all those curly braces, commas etc. YAML does just that!\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nAWS just announced support for YAML with CloudFormation templates. I would thoroughly recommend you check it out and start using YAML. It will make big difference to your productivity and, your templates will be much easier to read understand.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nYAML, like Coffeescript, Jade and Stylus, makes use of indenting in code to eliminate the need for braces and commas. When you're learning YAML, you can use a JSON to YAML converter (eg http:\/\/www.json2yaml.com) to convert your existing JSON to YAML.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\n(Very) Basics of YAML\u003C\/h3\u003E\n\u003Cb\u003ECollections using Indentation\u0026nbsp;\u003C\/b\u003Eeliminate the need for braces and commas with Objects:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cb\u003EJSON\u0026nbsp;\u003C\/b\u003E\u003Cbr \/\u003E\n\"WebsiteConfiguration\": {\u003Cbr \/\u003E\n\"IndexDocument\": \"index.html\",\u003Cbr \/\u003E\n\"ErrorDocument\": \"error.html\"\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cb\u003EYAML\u003C\/b\u003E\u003Cbr \/\u003E\nWebsiteConfiguration:\u003Cbr \/\u003E\n\u0026nbsp; IndexDocument: index.html\u003Cbr \/\u003E\n\u0026nbsp; ErrorDocument: error.html\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cb\u003ESequences with Dashes \u003C\/b\u003Eeliminate the need for square brackets and commas with Arrays:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cb\u003EJSON\u0026nbsp;\u003C\/b\u003E\u003Cbr \/\u003E\n[\u003Cbr \/\u003E\n\"S3Bucket\",\u003Cbr \/\u003E\n\"DomainName\"\u003Cbr \/\u003E\n]\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cb\u003EYAML\u003C\/b\u003E\u003Cbr \/\u003E\n\u0026nbsp; - S3Bucket\u003Cbr \/\u003E\n\u0026nbsp; - DomainName\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\nFull Example\u003C\/h3\u003E\nHere is a full example I created for S3. I'll let you be the judge which one is better!\u003Cbr \/\u003E\n\u003Ch4\u003E\nJSON:\u003C\/h4\u003E\n{\u003Cbr \/\u003E\n\"AWSTemplateFormatVersion\": \"2010-09-09\",\u003Cbr \/\u003E\n\"Description\": \"AWS CloudFormation Sample Template\",\u003Cbr \/\u003E\n\"Resources\": {\u003Cbr \/\u003E\n\"S3Bucket\": {\u003Cbr \/\u003E\n\"Type\": \"AWS::S3::Bucket\",\u003Cbr \/\u003E\n\"Properties\": {\u003Cbr \/\u003E\n\"AccessControl\": \"PublicRead\",\u003Cbr \/\u003E\n\"WebsiteConfiguration\": {\u003Cbr \/\u003E\n\"IndexDocument\": \"index.html\",\u003Cbr \/\u003E\n\"ErrorDocument\": \"error.html\"\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n},\u003Cbr \/\u003E\n\"DeletionPolicy\": \"Retain\"\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n},\u003Cbr \/\u003E\n\"Outputs\": {\u003Cbr \/\u003E\n\"WebsiteURL\": {\u003Cbr \/\u003E\n\"Value\": {\u003Cbr \/\u003E\n\"Fn::GetAtt\": [\u003Cbr \/\u003E\n\"S3Bucket\",\u003Cbr \/\u003E\n\"WebsiteURL\"\u003Cbr \/\u003E\n]\u003Cbr \/\u003E\n},\u003Cbr \/\u003E\n\"Description\": \"URL for website hosted on S3\"\u003Cbr \/\u003E\n},\u003Cbr \/\u003E\n\"S3BucketSecureURL\": {\u003Cbr \/\u003E\n\"Value\": {\u003Cbr \/\u003E\n\"Fn::Join\": [\u003Cbr \/\u003E\n\"\",\u003Cbr \/\u003E\n[\u003Cbr \/\u003E\n\"https:\/\/\",\u003Cbr \/\u003E\n{\u003Cbr \/\u003E\n\"Fn::GetAtt\": [\u003Cbr \/\u003E\n\"S3Bucket\",\u003Cbr \/\u003E\n\"DomainName\"\u003Cbr \/\u003E\n]\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n]\u003Cbr \/\u003E\n]\u003Cbr \/\u003E\n},\u003Cbr \/\u003E\n\"Description\": \"Name of S3 bucket to hold website content\"\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n}\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch4\u003E\nYAML:\u003C\/h4\u003E\n---\u003Cbr \/\u003E\nAWSTemplateFormatVersion: '2010-09-09'\u003Cbr \/\u003E\nDescription: AWS CloudFormation Sample Template\u003Cbr \/\u003E\nResources:\u003Cbr \/\u003E\n\u0026nbsp; S3Bucket:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Type: AWS::S3::Bucket\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Properties:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; AccessControl: PublicRead\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; WebsiteConfiguration:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; IndexDocument: index.html\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; ErrorDocument: error.html\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; DeletionPolicy: Retain\u003Cbr \/\u003E\nOutputs:\u003Cbr \/\u003E\n\u0026nbsp; WebsiteURL:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Value:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; Fn::GetAtt:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; - S3Bucket\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; - WebsiteURL\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Description: URL for website hosted on S3\u003Cbr \/\u003E\n\u0026nbsp; S3BucketSecureURL:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Value:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; Fn::Join:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; - ''\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; - - https:\/\/\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; - Fn::GetAtt:\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; - S3Bucket\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; \u0026nbsp; - DomainName\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Description: Name of S3 bucket to hold website content\u003Cbr \/\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Ca href=\"https:\/\/backspace.academy\/\" target=\"_blank\"\u003E\u003Cimg src=\"https:\/\/backspace.academy\/assets\/img\/logo.svg\" \/\u003E\u003C\/a\u003E\n"},"link":[{"rel":"replies","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/5633300852660274272\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/09\/yaml-and-cloudformation-yippee.html#comment-form","title":"3 Comments"},{"rel":"edit","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/5633300852660274272"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/5633300852660274272"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/09\/yaml-and-cloudformation-yippee.html","title":"YAML and CloudFormation. Yippee!!!"}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"thr$total":{"$t":"3"}},{"id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012.post-6695927890245298364"},"published":{"$t":"2016-09-04T20:51:00.004-07:00"},"updated":{"$t":"2016-09-26T06:29:18.130-07:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Denial of Service"},{"scheme":"http://www.blogger.com/atom/ns#","term":"IAM"},{"scheme":"http://www.blogger.com/atom/ns#","term":"NodeJS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Security"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Shared Responsibility"}],"title":{"type":"text","$t":"Shared Responsibility 2 - Using Dynamic CSS Selectors to stop the bots."},"content":{"type":"html","$t":"\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/media.licdn.com\/mpr\/mpr\/AAEAAQAAAAAAAATwAAAAJGU3YjNlNGFmLTc1NDQtNDJiMi1iYWYwLTRiOTA2ZTNjNjY0MQ.jpg\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" height=\"364\" src=\"https:\/\/media.licdn.com\/mpr\/mpr\/AAEAAQAAAAAAAATwAAAAJGU3YjNlNGFmLTc1NDQtNDJiMi1iYWYwLTRiOTA2ZTNjNjY0MQ.jpg\" width=\"640\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nIn my \u003Ca href=\"http:\/\/blog.backspace.academy\/2016\/08\/shared-responsibility-stopping-threats.html\"\u003Elast post\u003C\/a\u003E I talked about techniques to stop malicious web automation services at the source before they reach AWS infrastructure. Now we will get our hands dirty with some code to put it into action. Don't worry if you are not an experienced coder, you should still be able to follow along.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\nHow do Bot scripts work?\u003C\/h3\u003E\nA rendered web page contains a Document Object Model (DOM). The DOM defines all the elements on the page such as forms and input fields. Bots mimic a real user that enters information in fields, clicks on buttons etc. To do this the bot needs to identify the relevant elements in the DOM. DOM elements are identified using CSS selectors. Bot scripts consist of a series of steps that detail CSS selectors and what action to perform on them.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nThe DOM structure and elements of a page can be quickly identified using a browser. Pressing F12 in your browser will launch developer tools with this information:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/developer.chrome.com\/devtools\/images\/devtools-window.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" height=\"230\" src=\"https:\/\/developer.chrome.com\/devtools\/images\/devtools-window.png\" width=\"640\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nTo see specific details of a DOM element simply right click on the element on the page and select 'inspect':\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/1.bp.blogspot.com\/-ZBXiW_-KUqE\/V8yof19_FhI\/AAAAAAAAAV0\/xn6pkztN924SlSN7lEQPVJPrSLsPOya-gCLcB\/s1600\/dom-inspect.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/1.bp.blogspot.com\/-ZBXiW_-KUqE\/V8yof19_FhI\/AAAAAAAAAV0\/xn6pkztN924SlSN7lEQPVJPrSLsPOya-gCLcB\/s1600\/dom-inspect.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nThis will open up the developer tools with the element identified. You can get the CSS selector for the element easily by again right clicking on the element in the developer tools:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/2.bp.blogspot.com\/-p9sbSmdhswM\/V8ypdqXodEI\/AAAAAAAAAV4\/mUrbDihE3nMDUAzCJ_EXNJI60fVM6Kt-wCLcB\/s1600\/dom-selector.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/2.bp.blogspot.com\/-p9sbSmdhswM\/V8ypdqXodEI\/AAAAAAAAAV4\/mUrbDihE3nMDUAzCJ_EXNJI60fVM6Kt-wCLcB\/s1600\/dom-selector.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nNote that this will be only one representation of the element as a CSS selector (generally the shortest one). There are a number of ways an element can be defined as a CSS selector including:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cul\u003E\n\u003Cli\u003Eid name\u003C\/li\u003E\n\u003Cli\u003Einput name\u003C\/li\u003E\n\u003Cli\u003Eclass names\u003C\/li\u003E\n\u003Cli\u003EDOM traversal e.g. defining its chain of parent elements in the DOM\u003C\/li\u003E\n\u003Cli\u003EText inside the element using Jquery ':contains'.\u003C\/li\u003E\n\u003C\/ul\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\nDynamic CSS Selectors\u003C\/h3\u003E\nTo make life difficult to develop bot scripts you can use dynamic CSS selectors. Instead of creating the same CSS selectors each time your page is rendered, you can look at changing these randomly each time.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nWhen using NodeJS and Express this is quite straightforward as your are already rendering pages on the server. Simply introduce some code to mix this up a bit.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ch3\u003E\nLet's Start\u003C\/h3\u003E\n\u003Cbr \/\u003E\nFirst of all set up an EC2 instance with NodeJS and Express set up to render pages. If you are unsure you can view the video below:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ca href=\"https:\/\/vimeo.com\/145017165\" target=\"_blank\"\u003Ehttps:\/\/vimeo.com\/145017165\u003C\/a\u003E\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nTo save you typing, the \u003Ca href=\"https:\/\/gist.github.com\/BackSpaceTech\/41ed0973b96cf1360dc788ad5219a7b9\" target=\"_blank\"\u003Ecode is available at Gist\u003C\/a\u003E\u0026nbsp;(also Blogger tends to screw up code when it is published).\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nNow let's change index.js to create a simple login form.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nPoint your browser to the public IP address of your instance to check everything is ok. e.g. xxx.xxx.xxx.xxx:8080\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nNow change the index.js file to include a dynamicCSS function :\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cpre class=\"brush: js\"\u003Eapp.get('\/', function(request, response) {\n  response.send(dynamicCSS())\n})\n\nfunction dynamicCSS(){\n x = ''\n x += '\u003Cform\u003E\n';\n x += '\u003Cbr \/\u003E\n\u003Ch1\u003E\nPlease Login\u003C\/h1\u003E\n;\n x += '\u003Cinput id=\"username\" name=\"username\" placeholder=\"Enter Username\" type=\"text\" \/\u003E';\n x += '\u003Cinput id=\"password\" name=\"password\" placeholder=\"Enter Password\" type=\"password\" \/\u003E'; \n x += '\u003Cbutton type=\"submit\"\u003ELog in\u003C\/button\u003E'\n x += '\u003C\/form\u003E\n';\n return x\n}\n\u003C\/pre\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nNow do npm start at the command line of your ec2 instance and refresh the browser page. You will now see our very simple login form:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/1.bp.blogspot.com\/-p9LLTCAWglQ\/V8zMfrp6eDI\/AAAAAAAAAWM\/gahpx2v92NIfU6tRi2aH8owa7SbkCO8mQCLcB\/s1600\/login.PNG\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" height=\"74\" src=\"https:\/\/1.bp.blogspot.com\/-p9LLTCAWglQ\/V8zMfrp6eDI\/AAAAAAAAAWM\/gahpx2v92NIfU6tRi2aH8owa7SbkCO8mQCLcB\/s320\/login.PNG\" width=\"320\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nThe problem with this form is that it is really easy to identify the dom elements required to login. The id, name, placeholder all refer to username or password.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nNow let's change our code and introduce dynamically created CSS selectors.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cpre class=\"brush: js\"\u003Evar loginElements = {\n username: '',\n password: ''\n }\n\nfunction dynamicCSS(){\n var username = randomString()\n var password = randomString()\n loginElements.username = username\n loginElements.password = password \n x = ''\n x += '\u003Cform\u003E\n'\n x += '\u003Cbr \/\u003E\n\u003Ch1\u003E\nPlease Login\u003C\/h1\u003E\n'\n x += '\u003Cinput id=\"' + username + '\" name=\"' + username + '\" placeholder=\"Enter Username\" type=\"text\" \/\u003E'\n x += '\u003Cinput id=\"' + password + '\" name=\"' + password + '\" placeholder=\"Enter Password\" type=\"password\" \/\u003E'\n x += '\u003Cbutton type=\"submit\"\u003ELog in\u003C\/button\u003E'\n x += '\u003C\/form\u003E\n'\n return x\n}\n\nfunction randomString(){\n chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split('')\n chars.sort(function() {\n   return 0.5 - Math.random()\n })\n return chars.splice(0, 8).toString().replace(\/,\/g, '')\n}\n\u003C\/pre\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nThis now generates a random string for the id and name tags of the input elements. This makes it not possible to use these in a reliable bot script. If you do npm start again and view the the view the element in developer tools you can see the random strings.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nWe now need to look at the other ways our elements can be identified as CSS selectors. As you can see the text \"username\" and \"password\" is still used in the placeholders and input type tag. Also the DOM structure itself doesn't change dynamically, making it possible to reference the element through traversing the DOM structure.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nWe will address both problems by creating random decoy input elements with the same parameters. The CSS position property will allow us to stack them on top of each other so that the decoy elements are not visible on the page:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cpre class=\"brush: js\"\u003Eapp.get('\/', function(request, response) {\n  response.send(dynamicCSS())\n})\n\nvar loginElements = {\n  username: '',\n  password: ''\n}\n\nfunction dynamicCSS(){\n  var username, password\n  x = ''\n  x += '\u003Cform\u003E\n'\n  x += '\u003Cbr \/\u003E\n\u003Ch1\u003E\nPlease Login\u003C\/h1\u003E\n'\n  y = Math.floor((Math.random()*5)) + 2\n  for (var a=0; a\u003Cy a=\"\" class=\"username\" id=\"' + username + '\" input=\"\" name=\"' + username + '\" password=\"randonString()\" placeholder=\"Enter Username\" type=\"text\" username=\"randonString()\" x=\"\"\u003E'\n    x += '\u003Cinput class=\"password\" id=\"' + password + '\" name=\"' + password + '\" placeholder=\"Enter Password\" type=\"password\" \/\u003E'\n    loginElements.username = username\n    loginElements.password = password\n  }\n  x += '\u003Cbutton class=\"btnSubmit\" type=\"submit\"\u003ELog in\u003C\/button\u003E'\n  x += '\u003C\/y\u003E\u003C\/form\u003E\n'\n  return x\n}\n\nfunction randonString(){\n  chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split('')\n  chars.sort(function() {\n  return 0.5 - Math.random()\n  })\n  return chars.splice(0, 8).toString().replace(\/,\/g, '')\n}\n\n\u003C\/pre\u003E\n\u003Cbr \/\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\nNow when you view the DOM in your browser developer tools, \u0026nbsp;you can see the decoy input elements created underneath the real input element. If you refresh your browser you will see a different number of elements created each time (between 1 and 5 created).\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/3.bp.blogspot.com\/-znOd_64MkUE\/V8zn0_MJ-AI\/AAAAAAAAAWc\/AWrsqzkNfp4eWSuw80Uha-3sJjFp_-QQgCLcB\/s1600\/dom-dynamic.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/3.bp.blogspot.com\/-znOd_64MkUE\/V8zn0_MJ-AI\/AAAAAAAAAWc\/AWrsqzkNfp4eWSuw80Uha-3sJjFp_-QQgCLcB\/s1600\/dom-dynamic.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nThe bot creator can no longer use the username and password placeholders or input types to identify the elements. They can also not use the DOM structure to traverse through the DOM as this is changing also. As pointed out by a reader of this post (thanks Vadim!), you should also put some random inputs after to handle jquery \":last\". A good place would be underneath your logo.\u003Cbr \/\u003E\n\u003Cpre class=\"brush: js\"\u003Ey = Math.floor((Math.random()*5)) + 2\nfor (var a=0; a\u003Cy a=\"\" class=\"username\" id=\"' + username + '\" input=\"\" name=\"' + username + '\" password=\"randonString()\" placeholder=\"Enter Username\" type=\"text\" username=\"randonString()\" x=\"\"\u003E'\n  x += '\u003Cinput class=\"password\" id=\"' + password + '\" name=\"' + password + '\" placeholder=\"Enter Password\" type=\"password\" \/\u003E'\n  loginElements.username = username\n  loginElements.password = password\n}\nfor (var a=0; a\u003Cy a=\"\" class=\"username\" id=\"' + username + '\" input=\"\" name=\"' + username + '\" password=\"randonString()\" placeholder=\"Enter Username\" type=\"text\" username=\"randonString()\" x=\"\"\u003E'\n  x += '\u003Cinput class=\"password\" id=\"' + password + '\" name=\"' + password + '\" placeholder=\"Enter Password\" type=\"password\" \/\u003E'\n  document.getElementById(username).style.visibility = \"hidden\";\n  document.getElementById(password).style.visibility = \"hidden\";\n}\n\u003C\/y\u003E\u003C\/y\u003E\u003C\/pre\u003E\n\u003Cbr \/\u003E\nThe next thing a bot script can do is click on an x-y position on the screen. We can handle this by randomly changing the position of the elements.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Cpre class=\"brush: js\"\u003Evar loginElements = {\n username: '',\n password: ''\n }\n\nfunction dynamicCSS(){\n  var username, password\n  x = ''\n  if ((Math.random()*2) \u0026gt; 1)\n    x += '\u003Cstyle\u003E.btnSubmit,.password,.username{position:absolute;left:10}.username{top:50px}.password{top:80px}.btnSubmit{top:110px}\u003C\/style\u003E'\n  else\n    x += '\u003Cstyle\u003E.btnSubmit,.password,.username{position:absolute;left:10}.username{top:80px}.password{top:110px}.btnSubmit{top:140px}\u003C\/style\u003E'\n  x += '\u003Cform\u003E\n'\n  x += '\u003Cbr \/\u003E\n\u003Ch1\u003E\nPlease Login\u003C\/h1\u003E\n'\n  y = Math.floor((Math.random()*5)) + 2\n  for (var a=0; a\u003Cy a=\"\" class=\"username\" id=\"' + username + '\" input=\"\" name=\"' + username + '\" password=\"randonString()\" placeholder=\"Enter Username\" type=\"text\" username=\"randonString()\" x=\"\"\u003E'\n    x += '\u003Cinput class=\"password\" id=\"' + password + '\" name=\"' + password + '\" placeholder=\"Enter Password\" type=\"password\" \/\u003E'\n    loginElements.username = username\n    loginElements.password = password\n  }\n  x += '\u003Cbutton class=\"btnSubmit\" type=\"submit\"\u003ELog in\u003C\/button\u003E'\n  x += '\u003C\/y\u003E\u003C\/form\u003E\n'\n  return x\n}\nfunction randomString(){\n chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'.split('')\n chars.sort(function() {\n   return 0.5 - Math.random()\n })\n return chars.splice(0, 8).toString().replace(\/,\/g, '')\n}\n\u003C\/pre\u003E\n\u003Cbr \/\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cdiv\u003E\nThe position of the input elements is now random. This currently only has two positions but you can elaborate on this to create many possible combinations of positions. You may also make your login form inside a modal window that changes position on the screen.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nIf want to go further you can look having two login forms, username followed by password. Or even better, randomly change between the two.\u003C\/div\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cdiv\u003E\nWe have now addressed the possible techniques a bot creator can use to identify your input elements and login to your site.\u003C\/div\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cdiv\u003E\nCongratulations, you made it to the end!\u003C\/div\u003E\n\u003Ch3\u003E\nWhat's next?\u003C\/h3\u003E\nIn \u003Ca href=\"http:\/\/blog.backspace.academy\/2016\/09\/shared-responsibility-3-identify-and.html\" target=\"_blank\"\u003Emy next post\u003C\/a\u003E I will introduce techniques to identify bots and then look at launching a counter attack on the bot to crash it after it has been positively identified.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nBe sure to subscribe to the blog so that you can get the latest updates.\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nFor more AWS training and tutorials check out\u0026nbsp;\u003Ca href=\"https:\/\/backspace.academy\/\"\u003Ebackspace.academy\u003C\/a\u003E\n\u003Ca href=\"https:\/\/backspace.academy\/\" target=\"_blank\"\u003E\u003Cimg src=\"https:\/\/backspace.academy\/assets\/img\/logo.svg\" \/\u003E\u003C\/a\u003E"},"link":[{"rel":"replies","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/6695927890245298364\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/09\/shared-responsibility-2-using-dynamic.html#comment-form","title":"2 Comments"},{"rel":"edit","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/6695927890245298364"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/6695927890245298364"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/09\/shared-responsibility-2-using-dynamic.html","title":"Shared Responsibility 2 - Using Dynamic CSS Selectors to stop the bots."}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/1.bp.blogspot.com\/-ZBXiW_-KUqE\/V8yof19_FhI\/AAAAAAAAAV0\/xn6pkztN924SlSN7lEQPVJPrSLsPOya-gCLcB\/s72-c\/dom-inspect.png","height":"72","width":"72"},"thr$total":{"$t":"2"}},{"id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012.post-1087529482847827039"},"published":{"$t":"2016-06-28T18:48:00.000-07:00"},"updated":{"$t":"2016-06-29T01:03:10.599-07:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"India"},{"scheme":"http://www.blogger.com/atom/ns#","term":"News"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Region"}],"title":{"type":"text","$t":"Welcome aboard India!"},"content":{"type":"html","$t":"\u003Ch2\u003E\nWelcome aboard India!\u003C\/h2\u003E\n\u003Ch3\u003E\nAWS Announces New Asia Pacific (Mumbai) Region\u003C\/h3\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003C\/div\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003C\/div\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003C\/div\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003C\/div\u003E\n\u003Cbr \/\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003C\/div\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003C\/div\u003E\n\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/1.bp.blogspot.com\/-ECuuSEKbcM4\/V3OAr5fpwuI\/AAAAAAAAAUY\/a7MBdpGCdiYaATvFk9b56_3oN7Mk9O-sACLcB\/s1600\/india-flag.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/1.bp.blogspot.com\/-ECuuSEKbcM4\/V3OAr5fpwuI\/AAAAAAAAAUY\/a7MBdpGCdiYaATvFk9b56_3oN7Mk9O-sACLcB\/s1600\/india-flag.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\n\u003Cbr \/\u003E\nAt last India has its own region with two availability zones. Much overdue but sure to be a popular decision. The following services are available in the new region:\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Certificate Manager (ACM)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS CloudFormation\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon CloudFront\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS CloudTrail\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon CloudWatch\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS CodeDeploy\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Config\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Direct Connect\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon DynamoDB\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Elastic Beanstalk\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon ElastiCache\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Elasticsearch Service\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon EMR\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Glacier\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Identity and Access Management (IAM)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Import\/Export Snowball\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Key Management Service (KMS)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Kinesis\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Marketplace\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS OpsWorks\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Redshift\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Relational Database Service (RDS) – all database engines including Amazon Aurora\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Route 53\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Simple Notification Service (SNS)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Simple Queue Service (SQS)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Simple Storage Service (S3)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; Amazon Simple Workflow Service (SWF)\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Support\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; AWS Trusted Advisor\u003Cbr \/\u003E\n\u0026nbsp; \u0026nbsp; VM Import\/Export\u003Cbr \/\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cdiv\u003E\nThe available \u0026nbsp;services will no doubt be expanded so be sure to check for more details at:\u003C\/div\u003E\n\u003Cdiv\u003E\n\u003Ca href=\"http:\/\/aws.amazon.com\/about-aws\/global-infrastructure\/regional-product-services\/\" target=\"_blank\"\u003Ehttp:\/\/aws.amazon.com\/about-aws\/global-infrastructure\/regional-product-services\/\u003C\/a\u003E\u003C\/div\u003E\n\u003Cdiv\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n"},"link":[{"rel":"replies","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/1087529482847827039\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/06\/welcome-aboard-india.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/1087529482847827039"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/1087529482847827039"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/06\/welcome-aboard-india.html","title":"Welcome aboard India!"}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/1.bp.blogspot.com\/-ECuuSEKbcM4\/V3OAr5fpwuI\/AAAAAAAAAUY\/a7MBdpGCdiYaATvFk9b56_3oN7Mk9O-sACLcB\/s72-c\/india-flag.png","height":"72","width":"72"},"thr$total":{"$t":"0"}},{"id":{"$t":"tag:blogger.com,1999:blog-4603622075690903012.post-192390212269295925"},"published":{"$t":"2016-06-07T11:18:00.001-07:00"},"updated":{"$t":"2016-06-07T12:00:39.049-07:00"},"category":[{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS"},{"scheme":"http://www.blogger.com/atom/ns#","term":"AWS Certified SysOps Administrator"},{"scheme":"http://www.blogger.com/atom/ns#","term":"Course"}],"title":{"type":"text","$t":"New Course AWS Certified SysOps Administrator!"},"content":{"type":"html","$t":"\u003Cdiv class=\"separator\" style=\"clear: both; text-align: center;\"\u003E\n\u003Ca href=\"https:\/\/4.bp.blogspot.com\/--NO8U-Steq0\/VzyTxPNYEQI\/AAAAAAAAARg\/qHfG5FYl04U5LzgOqTTWKhKxXC_ZKXffwCKgB\/s1600\/AWS-Certified-SysOps-Administrator-Associate.png\" imageanchor=\"1\" style=\"margin-left: 1em; margin-right: 1em;\"\u003E\u003Cimg border=\"0\" src=\"https:\/\/4.bp.blogspot.com\/--NO8U-Steq0\/VzyTxPNYEQI\/AAAAAAAAARg\/qHfG5FYl04U5LzgOqTTWKhKxXC_ZKXffwCKgB\/s1600\/AWS-Certified-SysOps-Administrator-Associate.png\" \/\u003E\u003C\/a\u003E\u003C\/div\u003E\n\u003Cdiv style=\"text-align: center;\"\u003E\n\u003Cbr \/\u003E\u003C\/div\u003E\n\u003Cbr \/\u003E\nThe much awaited AWS Certified SysOps Adminstrator Course has been released. Available with the AWS Certified Associate course. All existing members will have access!\u003Cbr \/\u003E\n\u003Cbr \/\u003E\n\u003Ca href=\"http:\/\/backspace.academy\/\" target=\"_blank\"\u003EBackSpace Academy\u003C\/a\u003E"},"link":[{"rel":"replies","type":"application/atom+xml","href":"http:\/\/learn-aws.blogspot.com\/feeds\/192390212269295925\/comments\/default","title":"Post Comments"},{"rel":"replies","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/06\/new-course-aws-certified-sysops.html#comment-form","title":"0 Comments"},{"rel":"edit","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/192390212269295925"},{"rel":"self","type":"application/atom+xml","href":"http:\/\/www.blogger.com\/feeds\/4603622075690903012\/posts\/default\/192390212269295925"},{"rel":"alternate","type":"text/html","href":"http:\/\/learn-aws.blogspot.com\/2016\/06\/new-course-aws-certified-sysops.html","title":"New Course AWS Certified SysOps Administrator!"}],"author":[{"name":{"$t":"BackSpace Academy"},"uri":{"$t":"http:\/\/www.blogger.com\/profile\/15061292652079774775"},"email":{"$t":"noreply@blogger.com"},"gd$image":{"rel":"http://schemas.google.com/g/2005#thumbnail","width":"16","height":"16","src":"https:\/\/img1.blogblog.com\/img\/b16-rounded.gif"}}],"media$thumbnail":{"xmlns$media":"http://search.yahoo.com/mrss/","url":"https:\/\/4.bp.blogspot.com\/--NO8U-Steq0\/VzyTxPNYEQI\/AAAAAAAAARg\/qHfG5FYl04U5LzgOqTTWKhKxXC_ZKXffwCKgB\/s72-c\/AWS-Certified-SysOps-Administrator-Associate.png","height":"72","width":"72"},"thr$total":{"$t":"0"}}]}});