
<!DOCTYPE html>
<!--[if lt IE 7 ]><html class="ie ie6" lang="en"> <![endif]-->
<!--[if IE 7 ]><html class="ie ie7" lang="en"> <![endif]-->
<!--[if IE 8 ]><html class="ie ie8" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!-->
<html lang="en">
<!--<![endif]-->
<head id="ctl00_Head1"><meta http-equiv="content-type" content="text/html; charset=utf-8" />
	<link rel="contents" title="Archive" href="/blog/archive" />
	<link rel="start" title="Robin Minto" href="/blog/" />
	<link type="application/rsd+xml" rel="edituri" title="RSD" href="https://robinminto.com/blog/rsd.axd" />
	<link type="application/rdf+xml" rel="meta" title="SIOC" href="https://robinminto.com/blog/sioc.axd" />
	<link type="application/apml+xml" rel="meta" title="APML" href="https://robinminto.com/blog/apml.axd" />
	<link type="application/rdf+xml" rel="meta" title="FOAF" href="https://robinminto.com/blog/foaf.axd" />
	<link type="application/rss+xml" rel="alternate" title="Robin Minto" href="https://feeds.feedburner.com/robinminto" />
	<link type="application/opensearchdescription+xml" rel="search" title="Robin Minto" href="https://robinminto.com/blog/opensearch.axd" />
	<link href="/Content/Auto/Global.css" rel="stylesheet" type="text/css" />
	<script type="text/javascript" src="/blog/en-gb.res.axd"></script>
	<script type="text/javascript" src="/Scripts/Auto/01-jquery-1.9.1.min.js"></script>
	<script type="text/javascript" src="/Scripts/Auto/02-jquery.cookie.js"></script>
	<script type="text/javascript" src="/Scripts/Auto/04-jquery-jtemplates.js"></script>
	<script type="text/javascript" src="/Scripts/Auto/05-json2.min.js"></script>
	<script type="text/javascript" src="/Scripts/Auto/blog.js"></script>

  <!-- Basic Page Needs
  ================================================== -->
  <meta charset="utf-8" />

  <!-- Mobile Specific Metas
  ================================================== -->
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />

  <!-- CSS
  ================================================== -->
  <link rel="stylesheet" href="../Custom/Themes/ResponsiveModern/stylesheets/base.css" /><link rel="stylesheet" href="../Custom/Themes/ResponsiveModern/stylesheets/skeleton.css" /><link rel="stylesheet" href="../Custom/Themes/ResponsiveModern/stylesheets/layout.css" />

  <!--[if lt IE 9]>
    <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
  <![endif]-->

  <!-- Favicons
  ================================================== -->
  <link rel="shortcut icon" href="../Custom/Themes/ResponsiveModern/images/favicon.ico" type="image/x-icon" /><link rel="apple-touch-icon" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon.png" /><link rel="apple-touch-icon" sizes="57x57" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-57x57.png" /><link rel="apple-touch-icon" sizes="72x72" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-72x72.png" /><link rel="apple-touch-icon" sizes="76x76" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-76x76.png" /><link rel="apple-touch-icon" sizes="114x114" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-114x114.png" /><link rel="apple-touch-icon" sizes="120x120" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-120x120.png" /><link rel="apple-touch-icon" sizes="144x144" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-144x144.png" /><link rel="apple-touch-icon" sizes="152x152" href="../Custom/Themes/ResponsiveModern/images/apple-touch-icon-152x152.png" />
	<meta name="description" content="Robin Minto - Software development, security and miscellany - Software development, security and miscellany" />
	<meta name="keywords" content="Alt.NET,BarCamp,Blog,BlogEngine.NET,Certified Ethical Hacker,Desired State Configuration,IIS,London .NET user group,Miscellany,Networking,PowerShell,Presentations,Security,Server configuration,Software development,Threat Management Gateway,Time" />
	<meta name="author" content="Robin Minto" /><link type="text/css" rel="stylesheet" href="/Styles/syntaxhighlighter/shCore.css" /><link type="text/css" rel="stylesheet" href="/Styles/syntaxhighlighter/shThemeDefault.css" /><title>
	Robin Minto | Software development, security and miscellany
</title></head>
<body>
  <form method="post" action="/blog/?feed=rss2" id="aspnetForm" class="body">
<div class="aspNetHidden">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="FJw/+1i8jVFyZu33pN5zqwzyEKM9oJR6AsT3DiwQnOvp2zT2St0FLmU+2JyP4egOLblXC2Gbh6ET4wx4El4zxn08w18=" />
</div>




  <!-- Primary Page Layout
  ================================================== -->

  <div class="container">
    <div class="two-thirds column heading">
      <p><a href="/blog/">Robin Minto</a></p>
      <span>Software development, security and miscellany</span>
    </div>
    <div class="one-third column">
      <ul>
        <li class="tile speaking"><a href="/blog/page/speaking">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.speaking.svg" />
          <span class="label">Speaking</span></a>
        </li>
        <li class="tile feed"><a href="https://feeds.feedburner.com/robinminto">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.rss.svg" />
          <span class="label">Subscribe</span></a>
        </li>
        <li class="tile contact"><a href="/blog/contact">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.draw.pencil.svg" />
          <span class="label">Contact</span></a>
        </li>
        <li class="tile linkedin"><a href="https://uk.linkedin.com/pub/robin-minto/22/496/799" target="_blank">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.linkedin.svg" />
          <span class="label">Linked In</span></a>
        </li>
        <li class="tile twitter">
          <a href="https://twitter.com/robinem" target="_blank">
            <img src="../Custom/Themes/ResponsiveModern/images/appbar.social.twitter.svg" />
            <span class="label">Twitter</span></a>
        </li>
        <li class="tile github">
          <a href="https://github.com/robinminto" target="_blank">
            <img src="../Custom/Themes/ResponsiveModern/images/appbar.social.github.octocat.solid.svg" />
            <span class="label">Github</span></a>
        </li>
      </ul>
    </div>
    <div class="two-thirds column">
      
  <div id="ctl00_cphBody_divError"></div>
  <div id="ctl00_cphBody_PostList1_posts" class="posts">
<div class="postItem">
    <h1><a href="/blog/post/2017/08/25/Certified-Ethical-Hacker">Certified Ethical Hacker?</a></h1>
    <p>This week, I took the Certified Ethical Hacker exam &ndash; again&hellip; The first attempt at the exam <a href="/blog/post/2017/08/09/Breaking-the-Certified-Ethical-Hacker-exam">didn&rsquo;t make for a happy story</a>. I was convinced that they couldn&rsquo;t possibly have lost all of my work &ndash; the database must have stored each answer as I submitted it, surely?!</p>
<p>I went backwards and forwards with EC-Council to no avail. They offered an &ldquo;upgrade&rdquo; to an exam held at a test centre but that was a step backwards as far as I was concerned. Having assured me that they&rsquo;d resolved the issue with the web app, I rescheduled the online exam. I&rsquo;ll come back to the exam process later but I want to talk about certifications in general, why I was looking at CEH certification and how I prepared for it.</p>
<p><a title="Multiple choice exam" href="https://www.flickr.com/photos/albertogp123/5843577306/"><img style="display: inline; background-image: none;" title="Exam" src="/blog/image.axd?picture=5843577306_1a98149efb_o.jpg" alt="Exam" width="620" height="411" border="0" /></a></p>
<h1>Certifications</h1>
<p>I&rsquo;ve been working in software development for a long time and I&rsquo;ve never felt a definite need for certification. I&rsquo;ve done a lot of recruitment over the years, I&rsquo;ve looked at a lot of software developer CVs and certifications have always been a bonus feature and never a requirement.</p>
<p><a href="https://en.wikipedia.org/wiki/Impostor_syndrome">Impostor syndrome</a> seems to be very <a href="https://www.hanselman.com/blog/ImAPhonyAreYou.aspx">common amongst software developers</a> and I count myself in that group. I have, from time to time, wondered if a certification would validate that I can actually develop software against a recognised standard, say <a href="https://www.microsoft.com/en-gb/learning/mcsd-certification.aspx">Microsoft Certified Solution Developer</a>.</p>
<p>Looking at the certifications available though, I&rsquo;ve never been content that they were validating the right thing so I&rsquo;ve focused on learning and continuous development, comparing notes with peers in the industry to benchmark myself.</p>
<p>So why did I even get into this process at all?</p>
<h1>Why I started on the path to CEH</h1>
<p>I&rsquo;ve been into security for years &ndash; it was probably down to <a href="https://en.wikipedia.org/wiki/WarGames">WarGames</a>. The school computer lab was the location of a <a href="https://en.wikipedia.org/wiki/Wargame_(hacking)">wargame</a> of a different type where we&rsquo;d pwn each other&rsquo;s accounts, or the teacher&rsquo;s. This was a more innocent time &ndash; a long time before the UK Computer Misuse Act!</p>
<p>Information security is intertwined with software development. The internet makes the software that we write accessible to users good and bad, and I&rsquo;ve always been very conscious of that. One of the earliest bits of professional software that I wrote would hash the contents of a website so that unauthorised modifications could be detected.</p>
<p>Security doesn&rsquo;t get enough attention from software developers though so I&rsquo;ve been speaking on the subject for a couple of years to developer user groups. I gave a <a href="https://www.meetup.com/dotnetoxford/events/241048316/">lightning talk on OWASP ZAP</a> at .NET Oxford recently. Here&rsquo;s a talk I did to <a href="https://www.meetup.com/London-NET-User-Group/events/228252750/">London .NET</a> at Skills Matter last year.</p>
<p><a title="Video of London .NET talk" href="https://skillsmatter.com/skillscasts/8447-security-basics-and-uncovering-the-power-of-the-graph"><img style="display: inline; background-image: none;" title="SkillsMatter-Security-basics" src="/blog/image.axd?picture=SkillsMatter-Security-basics.png" alt="SkillsMatter-Security-basics" width="620" height="318" border="0" /></a></p>
<p>I&rsquo;ve spoken at <a href="https://developerdeveloperdeveloper.com/">DDD Reading</a>, <a href="http://www.dddsouthwest.com/">DDD South West</a> and I&rsquo;m speaking about authentication at <a href="https://dddeastanglia.com/">DDD East Anglia</a> next month.</p>
<p><img style="display: inline; background-image: none;" title="DDD East Anglia" src="/blog/image.axd?picture=DDD_East_Anglia.png" alt="DDD East Anglia" width="620" height="440" border="0" /></p>
<p>I&rsquo;ve been to many events and user groups as an attendee and it&rsquo;s fantastic to give something back as a speaker. I&rsquo;ve been incredibly lucky to be chosen to speak at all of these events but I&rsquo;d like to do more. Along the way though, I&rsquo;ve felt that imposter syndrome creeping back in &ndash; why should these people spend their incredibly valuable time listening to me?</p>
<p>My job title has never been Security Consultant, Pen Tester or CISO but I&rsquo;ve got the knowledge to share. Wouldn&rsquo;t it be useful if I had a certificate to prove it!</p>
<p>Selecting the Certified Ethical Hacker certification was straightforward. I was familiar with that cert and the competing qualifications. CEH is broadly recognised, even approved for meeting US <a href="http://www.darkreading.com/risk-management/dod-approves-ethical-hacker-certification/d/d-id/1087269">Department of Defense job requirements</a>.</p>
<p>All I needed to do was pass the exam.</p>
<h1>Preparation</h1>
<p>With the knowledge in hand, I wondered if I really needed to spend &pound;4,000 for an intensive 12 hour a day, 5-day course to get a certification. Sitting the exam, without the training, is just $750 US.</p>
<p>It would have been unwise to sit the exam with no preparation even with a broad knowledge of infosec. I needed to make sure I&rsquo;d covered the syllabus. The key, for me, came from <a href="https://www.pluralsight.com/">Pluralsight</a>. They have a wide range of video-based training material and a <a href="https://www.pluralsight.com/paths/ethical-hacking">CEH track</a> from Troy Hunt and Dale Meredith.</p>
<p>I&rsquo;ve followed <a href="https://www.troyhunt.com/">Troy Hunt&rsquo;s blog</a> for years. I&rsquo;ve been to his <a href="https://www.troyhunt.com/workshops/">Hack Yourself First workshop</a>. He&rsquo;s a great public speaker. I didn&rsquo;t know much about Dale Meredith but I do know the efforts that Pluralsight and their authors go to in producing content so I was happy he&rsquo;d be able to deliver.</p>
<p>I work at <a href="https://www.bybox.com/">ByBox</a> and we encourage the team to use Pluralsight as part of their training. This means the Pluralsight subscription was ready to go.</p>
<p>There&rsquo;s a further reason why video-based training was a good way to go for me and it&rsquo;s an interesting one&hellip; cycling. Last year, I invested in a smart-trainer that turns a road bike into an interactive cycling game via <a href="http://zwift.com/">Zwift</a>. The photo below shows a similar setup to mine. This was great for improving my fitness over the winter but I found I could train and watch Pluralsight videos at the same time. Two types of training combined!</p>
<p><a title="Cycling turbo-trainer" href="https://www.flickr.com/photos/30478819@N08/32224903716/in/photolist-tTUr3z-tRyUuG-R6B4bd-xNwn1g-tBjfNL"><img style="display: inline; background-image: none;" title="32224903716_1fea5b4c40_k" src="/blog/image.axd?picture=32224903716_1fea5b4c40_k.jpg" alt="32224903716_1fea5b4c40_k" width="620" height="417" border="0" /></a></p>
<p>Handily, a <a href="https://www.humblebundle.com/">Humble Bundle</a> of security eBooks containing <a href="https://www.amazon.co.uk/CEH-v9-Certified-Ethical-Version/dp/1119252245">Certified Ethical Hacker Version 9 Study Guide</a> came up so I added that to the training (but not on the bike). I knew some memorisation of tools and processes would be required. For example, I don&rsquo;t spend every day using nmap and you&rsquo;re expected to know all of the <a href="https://nmap.org/book/man-briefoptions.html">command line options</a>.</p>
<p>At somewhere between 1.5x and 2x speed, I got through the 76 hour Pluralsight CEH track in around 40 hours. I had probably spent another 5 hours on extra learning. Was I ready?</p>
<h1>The Exam</h1>
<p>As I mentioned, my <a href="/blog/post/2017/08/09/Breaking-the-Certified-Ethical-Hacker-exam">first attempt at the CEH exam</a> didn&rsquo;t go well. As I started the four-hour exam at the second attempt, I did a bit of QA testing of my own. I talked about the mechanics of the exam process in that blog so I won&rsquo;t go into them here but having moved on to the second question, I went back to review the first, knowing that had caused an error last time round. Everything seemed to be working properly &ndash; perhaps I&rsquo;d get through this thing?</p>
<p>You&rsquo;re allowed nearly two minutes per question and I found that was plenty. To make sure I didn&rsquo;t run out of time inadvertently, I&rsquo;d mark questions for review where I wasn&rsquo;t comfortable with the answer so I could return to them later. I spent about an hour and a half answering all the questions and an extra 15 minutes going over questions that needed extra attention.</p>
<p>I probably spent some extra time trying to interpret the questions and answers. It was clear that they&rsquo;re not all from the same author &ndash; some aren&rsquo;t from native English speakers:</p>
<blockquote>
<p>Secure Sockets Layer (SSL) use the asymmetric encryption both (public/private key pair) to deliver the shared session key and to achieve a communication way</p>
</blockquote>
<p>I have a lot of respect for those writing in a second language. The English language is fluid and we&rsquo;re not computers so we can interpret meaning but I think clarity of questions would benefit everyone.</p>
<p>Infosec is a broad subject and the <a href="https://www.eccouncil.org/programs/certified-ethical-hacker-ceh/course-outline/">CEH syllabus</a> is sufficiently broad to match. It goes into enough depth so that you have a good understanding of the topics but there&rsquo;s always room to go deeper. Armed with this level of knowledge, it&rsquo;s easier to find out more. I&rsquo;m not likely to spend much time in buffer overflows but if I need to, I have a good start.</p>
<h1>The Result</h1>
<p>I did wonder how quickly I&rsquo;d get results from the online exam. Would the answers have to go for some sort of verification? I was very thankful that the result came immediately &ndash; I&rsquo;d passed.</p>
<p><a href="/blog/image.axd?picture=CEH-Certificate.png"><img style="display: inline; background-image: none;" title="CEH-Certificate" src="/blog/image.axd?picture=CEH-Certificate_thumb.png" alt="CEH-Certificate" width="620" height="490" border="0" /></a></p>
<p>Taking the exam twice was not what I had planned and I&rsquo;m relieved that the process is now complete. I do believe that &ldquo;every day&rsquo;s a school day&rdquo; and I&rsquo;ve certainly learnt through training for the CEH certification. I won&rsquo;t be standing up at speaking events with my certificate in hand but I will add it to the bio and hopefully people will feel it&rsquo;s worth seeing me speak. See you at the next one?</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 25 August 2017 at 7:14 AM
        <br />Tagged: <a href="/blog/category/Certified-Ethical-Hacker">Certified Ethical Hacker</a>, <a href="/blog/category/Security">Security</a>
        <div class="ratingcontainer" style="visibility:hidden">6d1d5d67-a3c8-4073-a485-dee98b7d103d|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2017/08/09/Breaking-the-Certified-Ethical-Hacker-exam">Breaking the Certified Ethical Hacker exam</a></h1>
    <p>Monday was an interesting day; I sat the Certified Ethical Hacker exam with the intention of receiving certification from EC Council. I'll leave my reasons for taking the exam for another post - hopefully one saying that I've passed…  <p><a title="Quiet please. Exam." href="https://www.flickr.com/photos/bluesquarething/6254931160"><img width="620" height="409" title="6254931160_8ced372b67_o6" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="Quiet please. Exam." src="/blog/image.axd?picture=6254931160_8ced372b67_o6.jpg" border="0"></a>  <p>It's been years since I last sat an exam. Back then, I would have been sat in an exam hall with pen and paper. But things have changed and exams can be taken online – remotely monitored with a proctor watching via webcam and screen-sharing. Great – I don’t even need to leave the house!  <p>To take the exam, you start a webcam and chat session with a proctor at a company like <a href="https://www.proctoru.com/">ProctorU</a>. They check your ID and you point your webcam around your workspace and around the room so they can see that you don’t have smartphones or any other way of cheating. It struck me that all those taking this “hacker” exam would be thinking about all the ways they could beat this system, if it weren’t for the “ethical” bit.  <p>The proctor then takes you to the exam website where you log in, prove that you’ve paid with a one-time voucher code and select the exam that you’re taking. The proctor logs in and you accept various conditions (no break for four hours!) and you’re ready to start. I won’t dwell on the fact that the proctor is using credentials that are clearly common to everyone at the company – it’s not the first time I’ve seen that. As with all hackers, this one is <a href="https://twitter.com/troyhunt/status/693164285049073665">wearing a hoodie</a> but this is an ethical hacker so it’s beige.  <p><a title="eccexam.com" href="https://www.flickr.com/photos/bluesquarething/6254931160"><img width="620" height="483" title="ECCExam4" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="eccexam.com" src="/blog/image.axd?picture=ECCExam4.png" border="0"></a>  <p>I went through this process and began my exam. There are 125 multiple choice questions to answer – select a radio button and click the Answer button and the website progresses to the next question. I’m assuming that this is a PHP web app by the file extension in the URL. It’s straightforward stuff – the browser submits the form and the website returns the next page of question and answers. There’s also a checkbox to mark a question for review and a drop down list containing all the questions that have been answered with a Review button next to it.</p> <p>I’m about 18 questions in and I think I’ve been a bit hasty on the previous question. I select it from the list and hit Review. That’s when I hit the first problem.</p> <p><a href="/blog/image.axd?picture=eccexam-error_thumb3.png"><img width="620" height="175" title="eccexam-error_thumb3" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="SQL error" src="/blog/image.axd?picture=eccexam-error_thumb3_thumb.png" border="0"></a></p> <p>Ok, so I get a page with an error message with SQL syntax error. I’ve redacted what would seem to be a database table name in the error message – I don’t want to be the one sharing their database schema around the web.</p> <p><blockquote>
Error: getRecordItem (&lt;TABLE NAME HERE&gt;), SQL request error #1 Incorrect syntax near the keyword 'AND'.</blockquote>
<p><a href="https://www.owasp.org/index.php/Improper_Error_Handling">Improper Error Handling</a> is covered in the OWASP Top 10 under <a href="https://www.owasp.org/index.php/Top_10_2017-A5-Security_Misconfiguration">Security Misconfiguration</a> but I don’t have time to worry about that during my exam. I get in touch with the proctor to see if they can help. They try refreshing the page and opening new browser windows and going back through the exam selection process but it’s no good – the error message seems to be here to stay. They escalate to a colleague who tries the same things with no success. My exam voucher code is single use so I can’t even restart the exam.</p>
<p>At this point, the proctor says “We’ve sent an email to our contacts and they should contact you within three to six days” and I’m shocked. I can’t compare the stress levels now to those I had during university exams but the adrenaline is flowing. I’ve got a busy work calendar at the moment and rescheduling isn’t going to be easy. I’ve got a conference call following the exam. I go and get my mobile phone (having asked permission!) and call the EC Council helpline.</p>
<p>I get various ring tones as the call is bounced around the world. There’s a delay of a few seconds and communicating is a challenge. A few emails and phone calls and some time later and my one-time voucher code has been reset and I can restart the exam.</p>
<p>At this point, it’s an hour and a half after I first started and I restart the exam. I need to take more care as I answer the questions this time as I’m not going to risk trying to review questions later for fear of the same problem re-occurring.</p>
<p>I make good progress and I have time to spare as I reach the end of the questions. I select the last answer option and hit the Answer button on question 125.</p>
<p><a href="/blog/image.axd?picture=eccexam-error_thumb5.png"><img width="620" height="175" title="eccexam-error_thumb5" style="border-width: 0px; padding-top: 0px; padding-right: 0px; padding-left: 0px; display: inline; background-image: none;" alt="SQL error, again" src="/blog/image.axd?picture=eccexam-error_thumb5_thumb.png" border="0"></a></p>
<p>Oh wow. My head is now in my hands as I start to think about what’s just happened. That error message again.</p>
<p>I contact the proctor. I’ve been handed over to a new person so I have to explain the situation again. Browser is refreshed. New tabs are opened. Error remains.</p>
<p>I fire off an email to EC Council technical support. The error message basically tells me that the answers are stored in a database so they should be able to retrieve them so I don’t have to re-sit the exam, right?</p>
<blockquote>
<p>Apologies for the inconvenience caused. 
<p>We have reset your voucher code. Please reschedule the exam date for tomorrow.<br><br>We appreciate your patience and understanding of this matter.</p></blockquote>
<p>I reply. Are they telling me that the answers aren’t stored in the database?</p>
<blockquote>
<p>We apologize for the inconvenience caused, we regret to inform you that as the exam was not submitted successfully due to the technical difficulties we do not have logs from your exam to issue you with your certification. 
<p>We are happy to help you with the exam voucher of your choice valid for a period of 1 year and you can proceed to reschedule your exam with it. 
<p>Have a nice day!</p></blockquote>
<p>I’ve replied again and I’m waiting for a response. Did the application really fail to store any of my answers to the database? Why would I repeat any exam that’s so likely to lose my data and waste my time? If ProctorU recorded my screen for the duration of the exam, can we rebuild the data? 
<p>For the answers to these questions and more, watch this space! 

    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 9 August 2017 at 7:38 AM
        <br />Tagged: <a href="/blog/category/Security">Security</a>
        <div class="ratingcontainer" style="visibility:hidden">964cbe54-53a9-411c-9b47-370dd4fc2208|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2017/03/03/AltNET-and-Me">Alt.NET and Me</a></h1>
    <h2>Microsoft, community and .NET Renaissance</h2> <p>I wasn’t there in the beginning. In 2003, whilst I was taking some time out to go snowboarding, a small group of pioneers were inciting the .NET revolution. Dissatisfied with the oppression of Microsoft, they wrought the iron of .NET into the sword of Alt in the fires of pain.</p> <p>Anyway, I was in the Alps and the snow was great! So much so that I went back in 2004.</p> <p>But the revolution was brewing.</p> <p><a href="/blog/image.axd?picture=IMGP1045_-_rotated.jpg"><img title="IMGP1045 - rotated" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="IMGP1045 - rotated" src="/blog/image.axd?picture=IMGP1045_-_rotated_thumb.jpg" width="618" height="823"></a></p> <h2>Every day’s a school day</h2> <blockquote>“You have to run just to keep up”</blockquote> <blockquote>— My old boss, around 1997.</blockquote> <p>The pace of change in software development is significant and “every day’s a school day” has epitomised my software development career, where it can feel like you’re running just to keep up. I could have learnt different things in different ways but I’ve never stopped learning.</p> <p>There have certainly been points at which my learning accelerated. One such moment is where new team members have joined the team and have brought new experience and insight. Another is joining the developer community.</p> <h2>Discovering community</h2> <p>Although I was learning, I was almost a <a href="https://www.hanselman.com/blog/DarkMatterDevelopersTheUnseen99.aspx">Dark Matter Developer</a>. I was getting stuff done but I was blissfully unaware of the vibrant community of developers that surrounded me. One of the team introduced me to the blog of Brighton (UK)-based developer <a href="http://mikehadlow.com/">Mike Hadlow</a>. It was reading the comments on <a href="https://mikehadlow.blogspot.co.uk/2008/08/taking-httpcontext-out-of-mvc-framework.html">this blog post</a> that I noticed a phrase that piqued my interest — “ALT.NET”.</p> <p><a href="/blog/image.axd?picture=2017-03-03_14_18_48-Code_rant_2.png"><img title="2017-03-03 14_18_48-Code rant" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="2017-03-03 14_18_48-Code rant" src="/blog/image.axd?picture=2017-03-03_14_18_48-Code_rant_thumb_2.png" width="362" height="401"></a></p> <p>What was this strange “ALT.NET UK” that they talked about? I Googled this magical thing and found that the Alt.NET UK conference was imminent — I registered immediately and I was in.</p> <p>I met an amazing group of people at the Alt.NET UK unconference (including Mike Hadlow!). That led me to the London .NET user group, coding dojos, Progressive.NET, OWASP, DevOpsDays and the list goes on. I have many friends from that first Alt.NET event.</p> <h2>What’s in a name?</h2> <blockquote>“There are only two hard things in Computer Science: cache invalidation and naming things, and off-by-one errors.”</blockquote> <blockquote>— Phil Karlton et al</blockquote> <p>In Computer Science, naming things is hard. The same applies here. As <a href="https://www.hanselman.com/blog/ScottGuMVCPresentationAndScottHaScreencastFromALTNETConference.aspx">Scott Hanselman said</a> around the time of the first US conference, the Alt.NET name is polarizing. Some took it to mean anti-Microsoft. As with others, I took “alternative” to mean something that embraces choice.</p> <p>Why shouldn’t we build software using any tools irrespective of where they come from? The key is that we build great software. The same is true of languages and frameworks. I love C# and .NET but if Python is more appropriate for a particular use case, use that. Why can’t we look at other the communities around other languages for inspiration too? We can, and that’s Alt.NET.</p> <p>There was <a href="http://blog.robustsoftware.co.uk/2009/05/new-name-for-altnet.html">a feeling that Alt.NET was elitist</a> and the Alt meant an alternative group of people. Perhaps. However, I wasn’t part of the elite and Alt.NET won me over. And the Alt.NET name still has a lot of power. It can be a rallying cry.</p> <h2>.NET Renaissance</h2> <p class="graf graf--p">I want a wider set of developers to discover a rich .NET ecosystem. Microsoft is treading a difficult path which seems to be guided by dragging large Enterprise customers using .NET Framework into the future that is .NET Core at the expense of new developers, who might struggle in adopting .NET Core. Will backwards compatibility and the complexity it brings mean that they choose PHP, Node.js, Go or something else instead?</p> <p class="graf graf--p">Microsoft is a very different to the organisation that it was in the last decade. There are great people there doing great things but it is a large organisation and can do a lot of damage with little missteps. I want to see Microsoft continue to foster the ecosystem without stifling it. Much progress has been made here. Visual Studio wizards allow you to choose a unit testing framework other than MSTest; Newtonsoft Json.NET and jQuery were embraced, and not extinguished. These are limited examples but show the right intent. But even then, when Microsoft “bless” something, does that mean the others can’t compete?</p> <p class="graf graf--p">.NET Core has amazing potential. It’s enabled a cross-platform world that was unthinkable at one time. It is even present in AWS Lambda ready for the next evolution of cloud computing. We have an opportunity to grasp all of that potential as a community and run with it.</p> <p class="graf graf--p">Ian Cooper has <a class="markup--anchor markup--p-anchor" href="https://medium.com/altdotnet/on-the-need-for-a-c-renaissance-634078d4e865#.y3q1nl3ew" target="_blank" data-href="https://medium.com/altdotnet/on-the-need-for-a-c-renaissance-634078d4e865#.y3q1nl3ew">detailed some of the reasons</a> we need to take up the baton. <a class="markup--anchor markup--p-anchor" href="https://medium.com/altdotnet/net-renaissance-32f12dd72a1#.rhsmxwndj" target="_blank" data-href="https://medium.com/altdotnet/net-renaissance-32f12dd72a1#.rhsmxwndj">Mark Rendle</a> and <a class="markup--anchor markup--p-anchor" href="https://medium.com/altdotnet/bring-back-alt-net-but-why-df6faf0f966b#.4exsv9sjq" target="_blank" data-href="https://medium.com/altdotnet/bring-back-alt-net-but-why-df6faf0f966b#.4exsv9sjq">Dylan Beattie</a> have already written much more about the possibilities. As Gáspár Nagy says, it’s “<a class="markup--anchor markup--p-anchor" href="https://medium.com/@gasparnagy/net-core-in-the-focus-of-c-renaissance-227ad8f59108#.vy2buybr5" target="_blank" data-href="https://medium.com/@gasparnagy/net-core-in-the-focus-of-c-renaissance-227ad8f59108#.vy2buybr5">high time to think positively</a>”. I’m certainly not the only one looking forward to being a part of the .NET Renaissance!</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 3 March 2017 at 5:21 PM
        <br />Tagged: <a href="/blog/category/AltNET">Alt.NET</a>, <a href="/blog/category/Software-development">Software development</a>
        <div class="ratingcontainer" style="visibility:hidden">b7d7ba33-1ad8-41d6-8f51-a9269d2de500|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2015/05/20/HTTP-Public-Key-Pinning-(HPKP)">HTTP Public Key Pinning (HPKP)</a></h1>
    <p>There’s a new HTTP header on the block -&nbsp;<a title="http://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning" href="https://en.wikipedia.org/wiki/HTTP_Public_Key_Pinning" style="line-height: 1.428571429;" rel="noreferrer">HTTP Public Key Pinning (HPKP)</a>. It allows the server to publish a security policy in the same vein as&nbsp;<a title="https://www.owasp.org/index.php/HTTP_Strict_Transport_Security" href="https://www.owasp.org/index.php/HTTP_Strict_Transport_Security" style="line-height: 1.428571429;">HTTP Strict Transport Security</a>&nbsp;and&nbsp;<a title="https://www.owasp.org/index.php/Content_Security_Policy" href="https://www.owasp.org/index.php/Content_Security_Policy" style="line-height: 1.428571429;">Content Security Policy</a>.</p><p>The&nbsp;<a title="https://tools.ietf.org/html/rfc7469" href="https://tools.ietf.org/html/rfc7469" style="line-height: 1.428571429;" rel="noreferrer">RFC</a>&nbsp;<span style="line-height: 1.428571429;">was published last month so browser support is limited,</span><span style="line-height: 1.428571429;">&nbsp;supported in <a href="https://blog.chromium.org/2014/08/chrome-38-beta-new-primitives-for-next.html" rel="noreferrer">Chrome 38</a>, <a href="https://developer.mozilla.org/en-US/Firefox/Releases/35" rel="noreferrer">Firefox 35</a>&nbsp;and newer. However, there are helpful articles from </span><a title="https://scotthelme.co.uk/hpkp-http-public-key-pinning/" href="https://scotthelme.co.uk/hpkp-http-public-key-pinning/" style="line-height: 1.428571429;" rel="noreferrer">Scott Helme</a>,&nbsp;<a title="https://timtaubert.de/blog/2014/10/http-public-key-pinning-explained/" href="https://timtaubert.de/blog/2014/10/http-public-key-pinning-explained/" style="line-height: 1.428571429;" rel="noreferrer">Tim Taubert</a>&nbsp;and <a href="https://blog.rlove.org/2015/01/public-key-pinning-hpkp.html" rel="noreferrer">Robert Love</a>&nbsp;on the topic and&nbsp;<a title="https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning" href="https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning" style="line-height: 1.428571429;">OWASP</a> has some general info on certificate and key pinning in general.<span style="line-height: 1.428571429;">&nbsp;Scott has even built support for HPKP reporting into his helpful reporting service -&nbsp;</span><a href="https://report-uri.io/" style="line-height: 1.428571429;">https://report-uri.io/</a><span style="line-height: 1.428571429;">.</span></p><p><span style="line-height: 1.428571429;">Although Chrome and Firefox will honour your public key pins, testing the header is slightly tricky as they haven't implemented reporting yet (as of&nbsp;</span><span style="line-height: 1.428571429;">Chrome 42 and Firefox 38). I spent some time trying to coax both into reporting, working under the assumption that they must have implemented the whole spec right? It seems not.</span></p><div>In writing this, I also wanted to note the command I used to calculate the certifcate digest that's used in the header. In contrast to other examples, this connects to a remote host to get the certificate (including allowing for SNI), outputs to a file and exits openssl when complete.</div><pre class="brush: shell;">echo | 
openssl s_client -connect robinminto.com:443 -servername robinminto.com |
openssl x509 -pubkey -noout | openssl pkey -pubin -outform der |
openssl dgst -sha256 -binary | base64 &gt; certdigest.txt</pre>
<p>I won't be using HPKP in my day job until reporting support is available and I can validate that the configuration won't break clients. There's great potential here though once the support is available.</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 20 May 2015 at 9:17 AM
        <br />Tagged: <a href="/blog/category/IIS">IIS</a>, <a href="/blog/category/Security">Security</a>, <a href="/blog/category/Server-configuration">Server configuration</a>
        <div class="ratingcontainer" style="visibility:hidden">af52abf9-e1d0-40ad-a740-8328d14009c6|1|5.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2014/11/20/Server-trials-and-trebuildulations">Server trials and “trebuildulations”</a></h1>
    <h2>trebuildulation</h2> <p><font color="#666666">[tree-bild-yuh-ley-shuh n]</font><br>noun<br><font color="#a5a5a5"><font color="#666666"><font color="#666666">plural noun:</font> </font><strong><font color="#666666">trebuildulations</font></strong><br></font>: grievous trouble or severe trial whilst rebuilding or repairing<br>: made up word<br>: nod to Star Trek<br><font color="#666666">"the trebuildulations of a server"</font><br></p> <p>What started with warning about disk space, turned into a complete server rebuild which occupied all of my free time this week. I’m writing down some of the issues for the benefit of my future self and others.</p> <h2>Old Windows</h2> <p>When I see a disk space warning, I head into the drive and look for things to delete. In this case, I immediately noticed <strong>Windows.old</strong> taking up 15GB – this remnant of the upgrade to Server 2012 R2 last year was ripe for removal.</p> <p>If this were Windows 7, I would run <a href="http://windows.microsoft.com/en-gb/windows7/how-do-i-remove-the-windows-old-folder">Disk Cleanup</a> but on Server that requires the <strong>Desktop Experience</strong> feature to be installed. It isn’t by default and can’t be removed once it is. So, I set about trying to <a href="https://serverfault.com/questions/545579/properly-remove-windows-old-on-hyper-v-server-2012-r2">remove the folder at the command line</a>.</p> <p>At this point, it seems I failed to remove the junctions from Windows.old but succeeded in taking ownership, resetting permissions and removing the folder. The folder was gone but all was not well. On restart, the Hyper-V management service wouldn’t start.</p> <p>I forget the error but I eventually determined that the permissions had been reset on C:\ProgramData\Application Data. Unrestricted by folder permissions, Windows links this folder to itself resulting in <a href="http://theadminguy.com/2012/10/17/the-circumstance-of-the-nested-application-data-folder/">C:\ProgramData\Application Data\Application Data\Application Data\Application Data\Application Data...</a> This causes lots of <a href="https://msdn.microsoft.com/en-gb/library/windows/desktop/aa365247%28v=vs.85%29.aspx">MAX_PATH</a> issues at the very least.</p> <p>Despite correcting the permissions, I wasn’t quite able to fix everything and Hyper-V continued to fail. A rebuild was in order.</p> <h2>We couldn't create a new partition</h2> <p>Microsoft have refined the Windows Server installation process over the years so that it is now normally relatively painless, even without an unattended install. Boot from a USB key containing the installation media, select some localisation options, enter a licence key and off it goes. Not this time.</p> <p>My RAID volume was visible to the installer and I could delete, create and format partitions but when I came to the next step in the process:</p> <blockquote> <p>We couldn't create a new partition or locate an existing one. For more information, see the Setup log files.</p></blockquote> <p>This foxed me for a while. I tried <a title="http://blogs.technet.com/b/mempson/archive/2012/12/13/windows-8-and-the-dreaded-couldn-t-create-a-new-partition.aspx" href="http://blogs.technet.com/b/mempson/archive/2012/12/13/windows-8-and-the-dreaded-couldn-t-create-a-new-partition.aspx">DISKPART from the recovery prompt</a>, I tried <a title="http://www.thirdtier.net/2013/06/windows-server-2012-to-rst-raid-0-error-windows-cant-be-installed-on-drive-0-partition-1-and-others/" href="http://www.thirdtier.net/2013/06/windows-server-2012-to-rst-raid-0-error-windows-cant-be-installed-on-drive-0-partition-1-and-others/">resetting disks to non-RAID</a> and I tried <a title="http://www.natestiller.com/2013/01/installing-windows-server-2012-or-windows-8-error-we-couldnt-create-a-new-partition-or-locate-an-existing-one-for-more-information-see-the-setup-log-files/" href="http://www.natestiller.com/2013/01/installing-windows-server-2012-or-windows-8-error-we-couldnt-create-a-new-partition-or-locate-an-existing-one-for-more-information-see-the-setup-log-files/">disabling S.M.A.R.T. in the BIOS</a>. Nothing worked. I did notice mention of removing USB devices and disconnecting other hard drives suggesting there’s some hidden limit on the number of drives or partitions that the installer can handle. I could have removed each of the three data drives one by one to see if that theory had merit but I decided to jump in and remove all three.</p> <p>Success! A short while later I had a working Windows Server 2012 R2.</p> <h2>Detached Disks in the Storage Pool</h2> <p>I reconnected the three data drives and now came time to see if Storage Spaces would come back online <a title="http://blogs.technet.com/b/askpfeplat/archive/2012/12/24/windows-server-2012-how-to-import-a-storage-pool-on-another-server.aspx" href="http://blogs.technet.com/b/askpfeplat/archive/2012/12/24/windows-server-2012-how-to-import-a-storage-pool-on-another-server.aspx">as promised</a>.</p> <p>The steps were straightforward:</p> <ul> <li><strong>Set Read-Write Access</strong> for the Storage Space  </li><li><strong>Attach Virtual Disk</strong> for each of the virtual disks  </li><li><strong>Online</strong> each of the disks</li></ul> <p>The disks were back online and the data was available. Great!</p> <p>This was a short-lived success story – the disks were offline after reboot and had to be re-attached. Thankfully, I was <a href="https://itkbase.wordpress.com/2013/01/30/windows-server-2012-storage-spaces-virtual-disks-detach-after-reboot/">not alone</a> and a PowerShell one-liner fixed the issue.</p><pre class="brush: ps;">Get-VirtualDisk | Set-VirtualDisk -IsManualAttach $False
</pre>
<h2>Undesirable Desired State Configuration Hang</h2>
<p>I thought I’d take the opportunity to switch my imperative PowerShell setup scripts for Desired State Configuration-based goodness. This was a pretty smooth process but there was one gotcha.</p>
<p>DSC takes care of silent MSI installations but EXE packages require the appropriate “/quiet” arguments. The result of missing arguments in my configuration script meant that DSC sat waiting for someone to click an invisible dialog box in the EXE’s installer.</p>
<p>Having fixed my script, I killed the PowerShell process and re-tried to be presented with this:</p>
<blockquote><pre>Cannot invoke the SendConfigurationApply method. The PerformRequiredConfigurationChecks method is in progress and must 
return before SendConfigurationApply can be invoked.</pre></blockquote>
<p>The issue even survived a reboot.</p>
<p>Again, <a title="http://www.beefycode.com/post/A-Bit-of-DSC-Frustration.aspx" href="http://www.beefycode.com/post/A-Bit-of-DSC-Frustration.aspx">I was not alone</a> and some more PowerShell later, my desired state is configured.</p>
<p>I’m pleased to report the server is back to a happy state and all is well in its world.</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 20 November 2014 at 12:35 PM
        <br />Tagged: <a href="/blog/category/Desired-State-Configuration">Desired State Configuration</a>, <a href="/blog/category/PowerShell">PowerShell</a>, <a href="/blog/category/Server-configuration">Server configuration</a>
        <div class="ratingcontainer" style="visibility:hidden">875afeb7-e6dc-4066-aeaa-64b71d282758|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2014/04/20/IIS-configuration-file-contention">IIS configuration file contention</a></h1>
    <p>I’ve been automating the configuration of IIS on Windows servers using PowerShell. I’ll tell anyone who’ll listen that PowerShell is awesome and combined with source control, it’s my way of avoiding <a href="http://martinfowler.com/bliki/SnowflakeServer.html">snowflake</a> servers.</p> <p>To hone the process, I’ll repeatedly build a server with all of it’s configuration from a clean image (strictly speaking, a Hyper-V checkpoint) and I’m occasionally getting an error in a configuration script that has previously worked:</p><pre class="brush: ps;">new-itemproperty : Filename: \\?\C:\Windows\system32\inetsrv\config\applicationHost.config 
Error: Cannot write configuration file
</pre>
<p>Why is this happening? The problem is intermittent so it’s difficult to say for sure but it does seem to occur more often if the IIS Management Console is open. My theory is that if the timing is right, Management Console has a lock on the config file when PowerShell attempts to write to it and this error occurs.</p><h2>UPDATE</h2><p>I'm now blaming AppFabric components for this issue. I noticed the workflow service was accessing the IIS config file and also found this article on the IIS forums - <a href="http://forums.iis.net/t/1178705.aspx" rel="noreferrer">AppFabric Services preventing programmatic management of IIS</a>. The workflow services weren't intentionally installed and we're using the AppFabric Cache client NuGet package so I've removed the AppFabric install completely and haven't had a recurrence of the problem.</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 20 April 2014 at 9:53 PM
        <br />Tagged: <a href="/blog/category/IIS">IIS</a>, <a href="/blog/category/PowerShell">PowerShell</a>, <a href="/blog/category/Server-configuration">Server configuration</a>
        <div class="ratingcontainer" style="visibility:hidden">850ec2c5-4fd2-4ec0-9cbf-41b473db0910|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2014/03/21/Disabling-contactless-payment-cards-or-preventing-card-clash-with-Oyster">Disabling contactless payment cards, or preventing “card clash” with Oyster</a></h1>
    <p>I’ve been carrying an RFID-based <a href="https://en.wikipedia.org/wiki/Oyster_card">Oyster card</a> for years. It’s a fantastic way to use the transport network in London especially if you pay-as-you-go rather than using a seasonal travelcard. You just “touch in and out” and fares are deducted.</p> <p>It’s no longer necessary to have to work out how many journeys you’re going to do to decide if you need a daily travelcard or not – the amount is automatically capped at the price of a daily travelcard, if you get to that point. “Auto top-up” means money is transferred from your bank to your card when you get below a certain threshold so you never have to visit a ticket office (especially given they’ve closed them all) or a machine. It’s amazing to think they’ve been around since 2003.</p> <p>More recently it’s possible to pay for travel with a contactless payment card a.k.a. Visa PayWave or Mastercard Paypass. However, that leads to problems if, like most people, you carry more than one card in your wallet or purse – the Oyster system may not be able to read your Oyster card or worse, if your contactless payment card is compatible, it takes payment from the first card it can communicate with. If you have an Oyster seasonal travelcard, you don’t want to pay again for your journey by paying with credit card.</p> <p>TFL have recently started promoting this phenomenon under the name “<a href="https://www.tfl.gov.uk/tickets/29475.aspx" target="_blank">card clash</a>”.</p> <p>There’s even a pretty animation:</p> <p><a href="https://www.youtube.com/watch?v=uwHeaZJQm3k"><img title="CardClashAnimation" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="CardClashAnimation" src="/blog/image.axd?picture=CardClashAnimation_1.png" width="473" height="275"></a></p> <p>I first noticed card clash in 2010 when I was issued a new credit card with contactless payment. It went straight in my wallet with my Oyster and other payment cards and the first time I tried to touch in by presenting my wallet (as I’ve always done with Oyster) – beeeep beeeep beeeep (computer says no).</p> <p>It didn’t take me long to work out that the Oyster reader couldn’t distinguish between two RFID-enabled cards. I soon had a solution in the form of <a href="https://en.wikipedia.org/wiki/OnePulse" target="_blank">Barclaycard OnePulse</a> – a combined Oyster and Visa card. Perfect!</p> <p><a href="/blog/image.axd?picture=OnePulseCard.jpg"><img title="OnePulseCard" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="OnePulseCard" src="/blog/image.axd?picture=OnePulseCard_thumb.jpg" width="234" height="149"></a></p> <p>I could now touch in and out without having to get my card out of my wallet again. But not for long…</p> <p>I don’t know about you but I like to carry more than one credit card so if one is declined or faulty, I can still buy stuff. I had a card from Egg Banking for that purpose. To cut a long story, slightly shorter, Egg were bought by Barclaycard who then replaced my card with a new contactless payment enabled card. Oh dear, card clash again.</p> <p>I wrote to Barclaycard to ask if they could issue a card without contactless functionality. Here’s the response I got:</p> <blockquote> <p>All core Barclaycards now come with contactless functionality; this is part of ensuring our cardholders are ready for the cashless payment revolution. A small number of our credit cards do not have contactless yet but it is our intention these will have the functionality in due course. That means we are unable to issue you a non-contactless card. </p> <p>Please be assured that contactless transactions are safe and acceptance is growing. It uses the same functionality as Chip and PIN making it safe, giving you the same level of security and as it doesn't leave your hand there is even less chance of fraud. </p> <p>I trust the information is of assistance. </p> <p>Should you have any further queries, do not hesitate to contact me again.</p></blockquote> <p>I was very frustrated by this – I was already ready for the “cashless payment revolution” with my OnePulse card! Now, I was back in the situation where I would have to take the right card out of my wallet – not the end of the world but certainly not the promised convenience either. Barclaycard’s answer is to <a href="http://www.thisismoney.co.uk/money/cardsloans/article-2329468/Barclaycard-said-Id-need-wallets-stop-randomly-paying-buses-contactless-card.html" target="_blank">carry two wallets</a> – helpful! </p> <p>I’m certainly <a href="https://groups.google.com/d/msg/uk.transport.london/az6ZRp4K55g/9zU6HEAHU1UJ" target="_blank">not the only one</a> who has issues with card clash. I’m not the only one to notice <a href="https://diamondgeezer.blogspot.co.uk/2014_02_01_archive.html#6010708602836388530" target="_blank">TFL’s campaign</a> to warn travellers of the impending doom as contactless payment cards become more common. </p> <p><a href="/blog/image.axd?picture=CardClash.jpg"><img title="CardClash" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="CardClash" src="/blog/image.axd?picture=CardClash_thumb.jpg" width="440" height="586"></a> </p> <blockquote class="twitter-tweet" lang="en"><p>Travel Tip: Contactless is coming. Get in the habit of separating contactless and Oyster cards to avoid card clash <a href="https://t.co/Wbrr9ieeQZ">pic.twitter.com/Wbrr9ieeQZ</a></p>&mdash; TfL Ways to Pay (@TfLWaystoPay) <a href="https://twitter.com/TfLWaystoPay/statuses/441524960197357569">March 6, 2014</a></blockquote> <script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script> <p>So what’s the solution? If your card company isn’t flexible about what type of cards they issue and you can’t change to one that is (I hear HSBC UK may still be issuing cards without contactless payment on request), another option is to disable the contactless payment functionality. Some people have taken to destroying the chip in the card by <a title="https://www.youtube.com/watch?v=PB1saQTCzvg" href="https://www.youtube.com/watch?v=oD1QwLkTlxw" target="_blank">putting a nail through it</a>, <a href="https://www.youtube.com/watch?v=e52WfJgXuXE" target="_blank">cutting it with a knife</a> or <a href="https://www.youtube.com/watch?v=c0vZigwn09I" target="_blank">zapping it</a>. However, that also destroys the chip and PIN functionality which seems over the top. You can probably use the magnetic strip to pay with your card but presenting a card with holes in it to a shop assistant is likely to raise concerns. </p> <p>RFID cards have an aerial which allows communication with the reader and supplies power to the chip via <a href="https://en.wikipedia.org/wiki/Electromagnetic_induction" target="_blank">electromagnetic induction</a> (the zapping technique above overloads the chip with a burst of energy by induction). This means we can disable RFID without disabling chip and PIN by breaking the aerial circuit, meaning no communication or induction. </p> <p>The aerial layout varies. I dissected an old credit card to get an idea where the aerial was in my card (soaking in acetone causes the layers of the card to separate). Here you can see that the aerial runs across the top and centre of the card. </p> <p><a href="/blog/image.axd?picture=20140321_095853.jpg"><img title="20140321_095853" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="20140321_095853" src="/blog/image.axd?picture=20140321_095853_thumb.jpg" width="570" height="325"></a></p> <p>There are some helpful x-rays on the interwebs now showing some alternate layouts.</p> <p><a href="/blog/image.axd?picture=CardXray.jpg"><img title="CardXray" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="CardXray" src="/blog/image.axd?picture=CardXray_thumb.jpg" width="620" height="448"></a></p> <p>The aerial can be broken with a <a href="http://feilipu.me/2013/07/16/paywave-paypass-deletion-via-rfid-antenna-kill/" target="_blank">hole punch</a> or <a href="http://www.instructables.com/id/How-to-Disable-Contactless-Payment-on-Your-Debit-C/?ALLSTEPS" target="_blank">soldering iron</a> but I’ve found that making a small cut across the aerial is sufficient. It’s not necessary to cut all the way through the card – all that’s needed is to cut through to the layer containing the aerial. Start with a shallow cut and make it deeper if required. From the images above, a cut to the top of the card is likely to disable most cards. </p> <p><a href="/blog/image.axd?picture=20140307_095731.jpg"><img title="20140307_095731" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="20140307_095731" src="/blog/image.axd?picture=20140307_095731_thumb.jpg" width="560" height="317"></a> </p> <p>The central cut on this card wasn’t effective. The cut at the top was. </p> <p>If you have an NFC-enabled smartphone, it’s possible to test the card to check that contactless is disabled. I’m using <a href="https://play.google.com/store/apps/details?id=com.nxp.taginfolite" target="_blank">NFC TagInfo</a> on a Samsung Galaxy Nexus. Here’s the card above before: </p> <p><a href="/blog/image.axd?picture=Screenshot_2014-03-07-09-32-26.png"><img title="Screenshot_2014-03-07-09-32-26" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="Screenshot_2014-03-07-09-32-26" src="/blog/image.axd?picture=Screenshot_2014-03-07-09-32-26_thumb.png" width="291" height="511"></a> </p> <p>and after the aerial is cut (the chip no longer registers): </p> <p><a href="/blog/image.axd?picture=Screenshot_2014-03-07-09-33-54.png"><img title="Screenshot_2014-03-07-09-33-54" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="Screenshot_2014-03-07-09-33-54" src="/blog/image.axd?picture=Screenshot_2014-03-07-09-33-54_thumb.png" width="197" height="346"></a> </p> <p>Job done! The card continues to work with chip and PIN but doesn’t interfere with Oyster. </p> <p>Barclaycard have thrown another spanner in the works for me – OnePulse is <a href="https://www.tfl.gov.uk/tickets/29678.aspx">being withdrawn</a>. The solution seems to be to switch to <a href="https://www.tfl.gov.uk/contactless" target="_blank">contactless payments instead of Oyster</a>. Here’s hoping that TFL can finish <a href="http://www.mayorwatch.co.uk/tfl-contradicts-boris-insists-there-is-no-plan-to-scrap-oyster/">implementing contactless payments</a> (promised “later in 2014”) before my OnePulse is withdrawn. </p> <p>Disclaimer: if you’re using sharp knives, have a responsible adult present. If you damage yourself or your cards, don’t blame me!</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 21 March 2014 at 3:33 AM
        <br />Tagged: <a href="/blog/category/Miscellany">Miscellany</a>
        <div class="ratingcontainer" style="visibility:hidden">45bd1747-14b6-4d6a-a732-f37873a72872|2|5.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2014/03/02/New-host-new-look-Azure-and-responsive-design-Part-2">New host, new look – Azure and responsive design. Part 2.</a></h1>
    <h2>Part 2. A new responsive design.</h2> <p>Mobile is the new black. Mobile phones are increasingly used to access the web and websites need to take that into account.</p> <p>I’m using BlogEngine.NET which can deliver pages using a different template to browsers with small screens but that’s not ideal for larger phones and tablets. However, there is a better way – <a href="https://en.wikipedia.org/wiki/Responsive_web_design" target="_blank">responsive web design</a>. With a responsive design, CSS media queries and flexible images provide a flexible layout that is adjusted based on the screen (or browser) size.</p> <p>The BlogEngine.NET team have recognised that responsive design is the way forward so the <a href="http://www.dotnetblogengine.net/post/blogenginenet-29-released.aspx" target="_blank">recently released</a> version uses the <a href="https://getbootstrap.com/" target="_blank">Bootstrap framework</a> for the default template and administration UI. They’ve done a great job.</p> <p><a href="/blog/image.axd?picture=BlogEngineResponsive.png"><img title="BlogEngineResponsive" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="BlogEngineResponsive" src="/blog/image.axd?picture=BlogEngineResponsive_thumb.png" width="616" height="374"></a></p> <p>As part of moving my blog to Windows Azure as described in <a href="/blog/post/2014/03/02/New-host-new-look-Azure-and-responsive-design-Part-1" target="_blank">part 1</a>, I felt a new look was in order but I didn’t want to use the new BlogEngine.NET template so set about designing my own.</p> <p>Bootstrap isn’t the only framework that can help you build a responsive design. There’s <a href="http://foundation.zurb.com/" target="_blank">Foundation</a>, <a href="http://html5boilerplate.com/" target="_blank">HTML5 Boilerplate</a>, <a href="http://www.99lime.com/elements/" target="_blank">HTML KickStart</a> and <a href="http://framelessgrid.com/" target="_blank">Frameless</a> to name a few. I wanted a framework without too much in-built styling. Although Bootstrap can be customised, there are a lot of choices if you take that route.</p> <p><a href="/blog/image.axd?picture=BootstrapChoices.png"><img title="BootstrapChoices" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="BootstrapChoices" src="/blog/image.axd?picture=BootstrapChoices_thumb.png" width="339" height="383"></a></p> <p>I chose <a href="http://www.getskeleton.com/" target="_blank">Skeleton</a> as the framework for my design. It’s a straightforward grid system with minimal styling. And I’ve retained the minimal styling, only introducing a few design elements. My design is inspired by the <a href="https://en.wikipedia.org/wiki/Metro_(design_language)" target="_blank">Microsoft design language</a> (formerly Metro) – that basically comes down to flat, coloured boxes. Can you tell I’m not a designer?</p> <p>An added complexity is the introduction of high pixel density displays such as Apple’s <a href="https://en.wikipedia.org/wiki/Retina_Display" target="_blank">Retina</a>. Images that look fine on a standard display, look poor on Retina and the like. Creating images with twice as many pixels is one solution but I chose the alternative route of <a href="https://en.wikipedia.org/wiki/Scalable_Vector_Graphics" target="_blank">Scalable Vector Graphics</a>. <a href="http://modernuiicons.com/">modernuiicons.com</a> provides an amazing range of icons (1,207 at time of writing), intended for Windows Phone but perfect for my design. They appear top-right and at the bottom of the blog.</p> <p>Another website that came in very handy was <a href="http://iconifier.net">iconifier.net</a> – icon generator for Apple and favicon icons.</p>   <p>So, I’m now running on Windows Azure with a new responsive design. Perhaps I’ll get round to writing some blog articles that justify the effort?</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 2 March 2014 at 6:18 PM
        <br />Tagged: <a href="/blog/category/Blog">Blog</a>
        <div class="ratingcontainer" style="visibility:hidden">f534d9ba-6513-4e8a-a692-ad98b3ac69a0|3|5.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2014/03/02/New-host-new-look-Azure-and-responsive-design-Part-1">New host, new look – Azure and responsive design. Part 1.</a></h1>
    <h2>Part 1. Getting up and running on Windows Azure.</h2> <p>Microsoft’s cloud computing platform has a number of interesting features but the ability to create, deploy and scale web sites is particularly interesting to .NET developers. Many ISPs offer .NET hosting but few make it as easy as Azure.</p> <p>The web server setup and maintenance is all taken care of and managed by Microsoft, which I already get with my current host Arvixe. However, apps can be deployed directly from GitHub and Bitbucket (and more) and it’s possible to scale to 40 CPU cores with 70 GB of memory with a few clicks. If you don’t need that level of performance, you might even be able to run on the free tier.</p> <p>Here’s how I got up and running (I’ve already gone through the process of setting up an Azure account).</p> <p>Create a new website from the gallery:</p> <p><a href="/blog/image.axd?picture=NewWebsiteFromGallery.png"><img title="NewWebsiteFromGallery" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="NewWebsiteFromGallery" src="/blog/image.axd?picture=NewWebsiteFromGallery_thumb.png" width="634" height="204"></a></p> <p>In the gallery, select BlogEngine.NET. Choose a URL (something.azurewebsites.net) and a region (I choose North or West Europe as those are closest to my location).</p> <p>Wait. 90 seconds later, a default BlogEngine.NET website is up and running.</p> <p>I’ve created a source control repository in Mercurial. This contains:</p> <ul> <li>extensions (in App_Code, Scripts and Styles)  <li>settings, categories, posts, pages (in App_Data)  <li>the new design for the blog (in Themes) – see <a href="/blog/post/2014/03/02/New-host-new-look-Azure-and-responsive-design-Part-2" target="_blank">part 2</a> </li></ul> <p>Next, I need to configure my web site to deploy from Bitbucket where I’ve pushed that repo. “Set up deployment from source control” is an option in the dashboard:</p> <p><a href="/blog/image.axd?picture=DeploymentFromSourceControl.png"><img title="DeploymentFromSourceControl" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="DeploymentFromSourceControl" src="/blog/image.axd?picture=DeploymentFromSourceControl_thumb.png" width="648" height="412"></a></p> <p>Select Bitbucket and you’ll be asked to log in and allow Azure to connect to your repos:</p> <p><a href="/blog/image.axd?picture=Bitbucket_1.png"><img title="Bitbucket" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="Bitbucket" src="/blog/image.axd?picture=Bitbucket_thumb_1.png" width="387" height="267"></a></p> <p>Azure will then deploy that repo to the website from the latest revision.</p> <p>All that’s left is to log into blog and make a couple of changes. Firstly, I delete the default blog article created by BlogEngine.NET. I’m displaying tweets on my blog using the “Recent Tweets” widget so I install that.</p> <p>I’m using a custom domain rather than something.azurewebsites.net. That means I have to scale up from the free tier to shared:</p> <p><a href="/blog/image.axd?picture=SharedScale.png"><img title="SharedScale" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="SharedScale" src="/blog/image.axd?picture=SharedScale_thumb.png" width="374" height="106"></a></p> <p>Windows Azure must verify that I am authorized to use my custom domain. I do this by making a DNS change (my DNS records are hosted with <a title="This is my referral link. Register via this and we both get one month free!" href="https://dnsimple.com/r/620d451e209af5" target="_blank">DNSimple</a>), adding a CNAME records pointing from <strong>awverify.www.robinminto.com</strong> to <strong>awverify.robinminto-com.azurewebsites.net</strong> and from <strong>awverify.robinminto.com</strong> to <strong>awverify.robinminto-com.azurewebsites.net</strong>. If I wasn’t using the domain at the time, I could have added the CNAME records without the awverify prefix. Verification step complete, I can then add the domain names to Azure.</p> <p><a href="/blog/image.axd?picture=ManageDomains.png"><img title="ManageDomains" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" border="0" alt="ManageDomains" src="/blog/image.axd?picture=ManageDomains_thumb.png" width="452" height="303"></a></p> <p>Finally, having checked everything is working properly I change the DNS entries (as above without the awverify prefix) to point to my new web site and it’s job done!</p> <p>I took the opportunity to update the design that I use. I’ll deal with that in <a href="/blog/post/2014/03/02/New-host-new-look-Azure-and-responsive-design-Part-2" target="_blank">part 2</a>.</p>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 2 March 2014 at 6:15 PM
        <br />Tagged: <a href="/blog/category/Blog">Blog</a>, <a href="/blog/category/BlogEngineNET">BlogEngine.NET</a>
        <div class="ratingcontainer" style="visibility:hidden">3c7f6305-ddc8-4b22-965a-6bc9be6bdf93|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>

<div class="postItem">
    <h1><a href="/blog/post/2013/10/03/Analysing-Forefront-TMG-logs">Analysing Forefront TMG logs</a></h1>
    <p>I’m lamenting the demise of <a href="http://blogs.technet.com/b/server-cloud/archive/2012/09/12/important-changes-to-forefront-product-roadmaps.aspx" target="_blank">Forefront TMG</a> but I still think it’s a great product and continue to use it. Of course, I’m currently planning what I’m going to replace it with but I expect it’ll have to be a combination of products to get the features that I need.</p>  <p>Anyway, I’m currently doing some log analysis and wanted to capture some useful information about the process. TMG is using SQL Server Express for logging and I want to do some analysis in SQL Server proper.</p>  <p>First, <a href="http://blogs.technet.com/b/isablog/archive/2010/03/31/how-to-view-tmg-logs-when-using-sql-server-express-for-logging.aspx" target="_blank">export the logs from TMG</a>. I won’t repeat the steps from that post but in summary:</p>  <ol>   <li>Run the <strong>Import and Export Data</strong> application (All Programs / Microsoft SQL Server 2008 / Import and Export Data). Run this elevated/<strong>as administrator</strong>. </li>    <li>Choose the database (not today’s databases or you’ll cause contention). </li>    <li>Select <strong>Flat File Destination</strong> and include <strong>Column names in the first data row</strong>. </li>    <li>Select <strong>Tab {t}</strong> as the <strong>Column delimiter</strong>. </li>    <li>Export. </li> </ol>  <p>I took the files from this export and wanted to import them into SQL Server. Rather than import everything into varchar fields, I wanted to reproduce the schema that TMG uses. I couldn’t find the schema on the interwebs so I grabbed the databases from an offline TMG and scripted the tables.</p>  <p>Here’s the script to create the FirewallLog table:</p>  <pre class="brush: sql; collapse: true;">CREATE TABLE [dbo].[FirewallLog](
    [servername] [nvarchar](128) NULL,
    [logTime] [datetime] NULL,
    [protocol] [varchar](32) NULL,
    [SourceIP] [uniqueidentifier] NULL,
    [SourcePort] [int] NULL,
    [DestinationIP] [uniqueidentifier] NULL,
    [DestinationPort] [int] NULL,
    [OriginalClientIP] [uniqueidentifier] NULL,
    [SourceNetwork] [nvarchar](128) NULL,
    [DestinationNetwork] [nvarchar](128) NULL,
    [Action] [smallint] NULL,
    [resultcode] [int] NULL,
    [rule] [nvarchar](128) NULL,
    [ApplicationProtocol] [nvarchar](128) NULL,
    [Bidirectional] [smallint] NULL,
    [bytessent] [bigint] NULL,
    [bytessentDelta] [bigint] NULL,
    [bytesrecvd] [bigint] NULL,
    [bytesrecvdDelta] [bigint] NULL,
    [connectiontime] [int] NULL,
    [connectiontimeDelta] [int] NULL,
    [DestinationName] [varchar](255) NULL,
    [ClientUserName] [varchar](514) NULL,
    [ClientAgent] [varchar](255) NULL,
    [sessionid] [int] NULL,
    [connectionid] [int] NULL,
    [Interface] [varchar](25) NULL,
    [IPHeader] [varchar](255) NULL,
    [Payload] [varchar](255) NULL,
    [GmtLogTime] [datetime] NULL,
    [ipsScanResult] [smallint] NULL,
    [ipsSignature] [nvarchar](128) NULL,
    [NATAddress] [uniqueidentifier] NULL,
    [FwcClientFqdn] [varchar](255) NULL,
    [FwcAppPath] [varchar](260) NULL,
    [FwcAppSHA1Hash] [varchar](41) NULL,
    [FwcAppTrusState] [smallint] NULL,
    [FwcAppInternalName] [varchar](64) NULL,
    [FwcAppProductName] [varchar](64) NULL,
    [FwcAppProductVersion] [varchar](20) NULL,
    [FwcAppFileVersion] [varchar](20) NULL,
    [FwcAppOrgFileName] [varchar](64) NULL,
    [InternalServiceInfo] [int] NULL,
    [ipsApplicationProtocol] [nvarchar](128) NULL,
    [FwcVersion] [varchar](32) NULL
) ON [PRIMARY]</pre>

<p>and here's the script to create the WebProxyLog table:</p>

<pre class="brush: sql; collapse: true;">CREATE TABLE [dbo].[WebProxyLog](
    [ClientIP] [uniqueidentifier] NULL,
    [ClientUserName] [nvarchar](514) NULL,
    [ClientAgent] [varchar](128) NULL,
    [ClientAuthenticate] [smallint] NULL,
    [logTime] [datetime] NULL,
    [service] [smallint] NULL,
    [servername] [nvarchar](32) NULL,
    [referredserver] [varchar](255) NULL,
    [DestHost] [varchar](255) NULL,
    [DestHostIP] [uniqueidentifier] NULL,
    [DestHostPort] [int] NULL,
    [processingtime] [int] NULL,
    [bytesrecvd] [bigint] NULL,
    [bytessent] [bigint] NULL,
    [protocol] [varchar](13) NULL,
    [transport] [varchar](8) NULL,
    [operation] [varchar](24) NULL,
    [uri] [varchar](2048) NULL,
    [mimetype] [varchar](32) NULL,
    [objectsource] [smallint] NULL,
    [resultcode] [int] NULL,
    [CacheInfo] [int] NULL,
    [rule] [nvarchar](128) NULL,
    [FilterInfo] [nvarchar](256) NULL,
    [SrcNetwork] [nvarchar](128) NULL,
    [DstNetwork] [nvarchar](128) NULL,
    [ErrorInfo] [int] NULL,
    [Action] [varchar](32) NULL,
    [GmtLogTime] [datetime] NULL,
    [AuthenticationServer] [varchar](255) NULL,
    [ipsScanResult] [smallint] NULL,
    [ipsSignature] [nvarchar](128) NULL,
    [ThreatName] [varchar](255) NULL,
    [MalwareInspectionAction] [smallint] NULL,
    [MalwareInspectionResult] [smallint] NULL,
    [UrlCategory] [int] NULL,
    [MalwareInspectionContentDeliveryMethod] [smallint] NULL,
    [UagArrayId] [varchar](20) NULL,
    [UagVersion] [int] NULL,
    [UagModuleId] [varchar](20) NULL,
    [UagId] [int] NULL,
    [UagSeverity] [varchar](20) NULL,
    [UagType] [varchar](20) NULL,
    [UagEventName] [varchar](60) NULL,
    [UagSessionId] [varchar](50) NULL,
    [UagTrunkName] [varchar](128) NULL,
    [UagServiceName] [varchar](20) NULL,
    [UagErrorCode] [int] NULL,
    [MalwareInspectionDuration] [int] NULL,
    [MalwareInspectionThreatLevel] [smallint] NULL,
    [InternalServiceInfo] [int] NULL,
    [ipsApplicationProtocol] [nvarchar](128) NULL,
    [NATAddress] [uniqueidentifier] NULL,
    [UrlCategorizationReason] [smallint] NULL,
    [SessionType] [smallint] NULL,
    [UrlDestHost] [varchar](255) NULL,
    [SrcPort] [int] NULL,
    [SoftBlockAction] [nvarchar](128) NULL
) ON [PRIMARY]</pre>

<p>TMG stores IPv4 and IPv6 addresses in the same field using as a UNIQUEIDENTIFIER. This means we have to parse them if we want to display a dotted quad, or at least we find <a href="http://www.eamonncc.nl/index.php?option=com_content&amp;view=article&amp;id=64:tsql-convert-ip-address-from-log-file-tmg-server&amp;catid=40:scripts-development&amp;Itemid=60&amp;lang=en" target="_blank">a function that will do it for us</a>.</p>

<p>Here’s my version:</p>

<pre class="brush: sql; collapse: true;">CREATE FUNCTION [dbo].[ufn_GetIPv4Address]
    (
      @uidIP UNIQUEIDENTIFIER
    )
RETURNS NVARCHAR(20)
AS 
    BEGIN
        DECLARE @binIP VARBINARY(4)  
        DECLARE @h1 VARBINARY(1) 
        DECLARE @h2 VARBINARY(1) 
        DECLARE @h3 VARBINARY(1)
        DECLARE @h4 VARBINARY(1)
        DECLARE @strIP NVARCHAR(20)

        SELECT  @binIP = CONVERT(VARBINARY(4), @uidIP) 
        SELECT  @h1 = SUBSTRING(@binIP, 1, 1) 
        SELECT  @h2 = SUBSTRING(@binIP, 2, 1) 
        SELECT  @h3 = SUBSTRING(@binIP, 3, 1) 
        SELECT  @h4 = SUBSTRING(@binIP, 4, 1) 
        SELECT  @strIP = CONVERT(NVARCHAR(3), CONVERT(INT, @h4)) + '.'
                + CONVERT(NVARCHAR(3), CONVERT(INT, @h3)) + '.'
                + CONVERT(NVARCHAR(3), CONVERT(INT, @h2)) + '.'
                + CONVERT(NVARCHAR(3), CONVERT(INT, @h1))

        RETURN @strIP 
    END  </pre>

<p><a href="https://technet.microsoft.com/en-us/library/cc441730.aspx" target="_blank">Action values</a> are stored as an integer so I’ve created a table to decode them:</p>

<pre class="brush: sql; collapse: true;">CREATE TABLE [dbo].[Action](
    [Id] [int] NOT NULL,
    [Value] [varchar](50) NOT NULL,
    [String] [varchar](50) NOT NULL,
    [Description] [varchar](255) NOT NULL,
 CONSTRAINT [PK_Action] PRIMARY KEY CLUSTERED ([Id] ASC)
)

INSERT INTO Action
        ( Id, Value, String, Description )
VALUES
(0, 'NotLogged', '-', 'No action was logged.'),
(1, 'Bind', 'Bind', 'The Firewall service associated a local address with a socket.'),
(2, 'Listen', 'Listen', 'The Firewall service placed a socket in a state in which it listens for an incoming connection.'),
(3, 'GHBN', 'Gethostbyname', 'Get host by name request. The Firewall service retrieved host information corresponding to a host name.'),
(4, 'GHBA', 'gethostbyaddr', 'Get host by address request. The Firewall service retrieved host information corresponding to a network address.'),
(5, 'Redirect_Bind', 'Redirect Bind', 'The Firewall service enabled a connection using a local address associated with a socket.'),
(6, 'Establish', 'Initiated Connection', 'The Firewall service established a session.'),
(7, 'Terminate', 'Closed Connection', 'The Firewall service terminated a session.'),
(8, 'Denied', 'Denied Connection', 'The action requested was denied.'),
(9, 'Allowed', 'Allowed Connection', 'The action requested was allowed.'),
(10, 'Failed', 'Failed Connection Attempt', 'The action requested failed.'),
(11, 'Intermediate', 'Connection Status', 'The action was intermediate.'),
(12, 'Successful_Connection', '- Initiated VPN Connection', 'The Firewall service was successful in establishing a connection to a socket.'),
(13, 'Unsuccessful_Connection', 'Failed VPN Connection Attempt', 'The Firewall service was unsuccessful in establishing a connection to a socket.'),
(14, 'Disconnection', 'Closed VPN Connection', 'The Firewall service closed a connection on a socket.'),
(15, 'User_Cleared_Quarantine', 'User Cleared Quarantine', 'The Firewall service cleared a quarantined virtual private network (VPN) client.'),
(16, 'Quarantine_Timeout', 'Quarantine Timeout', 'The Firewall service disqualified a quarantined VPN client after the time-out period elapsed.')</pre>

<p>The next step is to import the exported text files into the relevant table in SQL Server. Note that the SQL Server Import and Export Wizard has a default length of 50 characters for all character fields – that won’t be sufficient for much of the data. I used the schema as a reference to choose the correct lengths.</p>

<p>I can now look at the log data in ways that the log filtering can’t and without stressing the TMG servers.</p>

<pre class="brush: sql;">-- Outbound traffic ordered by connections descending
SELECT ApplicationProtocol, A.String AS Action, COUNT(*) 
FROM FirewallLog FL
INNER JOIN Action A ON A.Id = FL.Action
WHERE DestinationNetwork = 'External' AND FL.Action NOT IN (7)
GROUP BY ApplicationProtocol, A.String
ORDER BY COUNT(*) DESC


-- Successful outbound traffic ordered by connections descending
SELECT ApplicationProtocol, A.String AS Action, COUNT(*) 
FROM FirewallLog FL
INNER JOIN Action A ON A.Id = FL.Action
WHERE DestinationNetwork = 'External' AND A.String IN ('Initiated Connection')
GROUP BY ApplicationProtocol, A.String
ORDER BY COUNT(*) DESC


-- Successful outbound traffic showing source and destination IP addresses, ordered by connections descending
SELECT  ApplicationProtocol ,
        dbo.ufn_GetIPv4Address(SourceIP) AS SourceIP ,
        dbo.ufn_GetIPv4Address(DestinationIP) AS DestinationIP ,
        COUNT(*) AS Count
FROM    FirewallLog
WHERE   ApplicationProtocol IN ( 'HTTP', 'HTTPS', 'FTP' )
        AND DestinationNetwork = 'External'
        AND Action NOT IN ( 7, 8, 10, 11 )
GROUP BY ApplicationProtocol ,
        dbo.ufn_GetIPv4Address(SourceIP) ,
        dbo.ufn_GetIPv4Address(DestinationIP)
ORDER BY COUNT(*) DESC</pre>
    <div class="post-footer">
        By <a href="/author/Robin-Minto.aspx">Robin Minto</a>
        on 3 October 2013 at 4:10 PM
        <br />Tagged: <a href="/blog/category/Threat-Management-Gateway">Threat Management Gateway</a>
        <div class="ratingcontainer" style="visibility:hidden">69a7dd2e-dc30-430b-a939-0a02593485cb|0|.0|96d5b379-7e1d-4dac-a6ba-1e50db561b04</div>
        <div style="clear: both;"></div>
    </div>
    <div class="adminLinks">
        
    </div>
    <script type="text/javascript">
        function foo() {
            var p = $("[id$='_hlPrev']");
            var n = $("[id$='_hlNext']");

            if (p != null && p.html() != undefined && p.html().length > 0) {
                var newhtml = p.html().replace('&lt;&lt;', '');
                p.html(newhtml);
                p.addClass('nav-pre');
            }

            if (n != null && n.html() != undefined && n.html().length > 0) {
                var newhtml = n.html().replace('&gt;&gt;', '');
                n.html(newhtml);
                n.addClass('nav-nxt');
            }
        }
        foo();
    </script>
</div>
</div>

<div id="postPaging" style="display: none">
  <a id="ctl00_cphBody_PostList1_hlPrev" style="float:left">&lt;&lt; Older posts</a>
  <a id="ctl00_cphBody_PostList1_hlNext" style="float:right">Newer posts &gt;&gt;</a>
</div>

<div style="clear:both; display:block">
  <ul id="PostPager"><li class="PagerLinkDisabled">Newer posts</li><li class="PagerLinkCurrent">1</li><li class="PagerLink"><a href="/blog/?feed=rss2&amp;page=2">2</a></li><li class="PagerLink"><a href="/blog/?feed=rss2&amp;page=2">Older posts</a></li></ul>
</div>
  

    </div>
    <div class="one-third column">
      <div id="widgetzone_be_WIDGET_ZONE" class="widgetzone">

<div class="widget search">
    <div class="widget-content">
        <div id="searchbox">
            <input type="text" style="width: 72% !important" onblur="BlogEngine.searchClear('Enter search term or APML url','txt-fb38ecdd-5813-4d10-8c5f-8d901c7c731e')" onfocus="BlogEngine.searchClear('Enter search term or APML url','txt-fb38ecdd-5813-4d10-8c5f-8d901c7c731e')" onkeypress="if(event.keyCode==13) return BlogEngine.search('/blog/','txt-fb38ecdd-5813-4d10-8c5f-8d901c7c731e')" id="txt-fb38ecdd-5813-4d10-8c5f-8d901c7c731e" value="Enter search term or APML url" />
            <input type="button" onkeypress="BlogEngine.search('/blog/', 'txt-fb38ecdd-5813-4d10-8c5f-8d901c7c731e');" onclick="BlogEngine.search('/blog/', 'txt-fb38ecdd-5813-4d10-8c5f-8d901c7c731e');" id="searchbutton" value="Search" />
        </div>
    </div>
</div>
<div class="widget textbox">
        <a class="twitter-timeline" href="https://twitter.com/robinem" data-height="600">Tweets by robinem</a>
        <script>
        !function (d, s, id) {
            var js, fjs = d.getElementsByTagName(s)[0], p = /^http:/.test(d.location) ? 'http' : 'https';
            if (!d.getElementById(id)) {
                js = d.createElement(s);
                js.id = id;
                js.src = p + "://platform.twitter.com/widgets.js";
                fjs.parentNode.insertBefore(js, fjs);
            }
        }(document, "script", "twitter-wjs");
        </script>
</div>
<div class="widget textbox">
    <p>I'm a software developer/technical architect working for a logistics company in the UK.</p>
<p><a href="/blog/page/About-the-author-Robin-Minto">More...</a></p>
</div>
<div class="widget monthlist">
    <h4 class="widget-header">Older Posts</h4>
    <div class="widget-content">
        <ul id="monthList">
<li onclick="BlogEngine.toggleMonth(&#39;year2017&#39;)" class="year">2017
                <ul id="year2017" class="open">
                    <li><a href="/blog/2017/08/default">August</a> (2)</li>
                    <li><a href="/blog/2017/03/default">March</a> (1)</li>
                </ul>
            </li>
<li onclick="BlogEngine.toggleMonth(&#39;year2015&#39;)" class="year">2015
                <ul id="year2015" class="close">
                    <li><a href="/blog/2015/05/default">May</a> (1)</li>
                </ul>
            </li>
<li onclick="BlogEngine.toggleMonth(&#39;year2014&#39;)" class="year">2014
                <ul id="year2014" class="close">
                    <li><a href="/blog/2014/11/default">November</a> (1)</li>
                    <li><a href="/blog/2014/04/default">April</a> (1)</li>
                    <li><a href="/blog/2014/03/default">March</a> (3)</li>
                </ul>
            </li>
<li onclick="BlogEngine.toggleMonth(&#39;year2013&#39;)" class="year">2013
                <ul id="year2013" class="close">
                    <li><a href="/blog/2013/10/default">October</a> (1)</li>
                </ul>
            </li>
<li onclick="BlogEngine.toggleMonth(&#39;year2012&#39;)" class="year">2012
                <ul id="year2012" class="close">
                    <li><a href="/blog/2012/08/default">August</a> (1)</li>
                </ul>
            </li>
<li onclick="BlogEngine.toggleMonth(&#39;year2011&#39;)" class="year">2011
                <ul id="year2011" class="close">
                    <li><a href="/blog/2011/11/default">November</a> (1)</li>
                    <li><a href="/blog/2011/10/default">October</a> (2)</li>
                    <li><a href="/blog/2011/09/default">September</a> (1)</li>
                </ul>
            </li>
<li onclick="BlogEngine.toggleMonth(&#39;year2010&#39;)" class="year">2010
                <ul id="year2010" class="close">
                    <li><a href="/blog/2010/11/default">November</a> (1)</li>
                    <li><a href="/blog/2010/10/default">October</a> (1)</li>
                </ul>
            </li>
        </ul>
    </div>
</div></div>
    </div>
    <div class="sixteen columns">
      <ul>
        <li class="tile feed"><a href="https://feeds.feedburner.com/robinminto">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.rss.svg" />
          <span class="label">Subscribe</span></a>
        </li>
        <li class="tile contact"><a href="/blog/contact">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.draw.pencil.svg" />
          <span class="label">Contact</span></a>
        </li>
        <li class="tile archive"><a href="/blog/archive">
          <img src="../Custom/Themes/ResponsiveModern/images/appbar.folder.open.svg" />
          <span class="label">Archive</span></a>
        </li>
        
        <li class="tile logout"><a href="/blog/account/login.aspx">
            <img src="../Custom/Themes/ResponsiveModern/images/appbar.unlock.svg" />
            <span class="label">Log in</span></a>
        </li>
        
      </ul>
    </div>
    <div class="sixteen columns">
      <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons Licence" style="border-width:0" src="https://licensebuttons.net/l/by-sa/4.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International License</a>.
    </div>
    <div class="sixteen columns">
      <a href="/blog/page/attribution">Attribution</a>.
    </div>
  </div>
  <!-- container -->

  <!-- End Document
================================================== -->
  
<div class="aspNetHidden">

	<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="CA0B0334" />
</div>

<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-25517468-1']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>
<script type="text/javascript" src="/Scripts/highlighter" defer="defer" async="async"></script><script type="text/javascript" defer="defer">
</script>
</form>
</body>
</html>
