How I found one of the earliest browsers in history

Pablo Fernandez

Yesterday, the web celebrated its 25th birthday and to join in, I want a little story. A couple of years ago I found a NeXTcube. I’m not going to say where it is to avoid vandalism, but this is the story. Sir Tim Berners-Lee coded the earliest version of the web in his NeXTcube workstation when he was working at CERN, so, I was always interested in this machines, from a historical/playful point of view.

The cube that was in front of me was more or less abandoned and I asked the owner if I could play with it. He was very reticent but I was more relentless and I got to play with it. He told me that Next computer belonged, at one point, to CERN and that it has not been used since then. I decided to explore it.

The first interesting thing I found was a file…

View original post 337 more words


Wednesday Shorts: Sintel

Cain S. Latrani

One of the things I look for in the short films I share here is a story that has heart, the kind that is able to evoke a genuine emotion. While I sometimes veer off for something that is just straight up funny, such as last weeks Tone Deaf, my real goal is to help showcase the kind of work that doesn’t always get the attention it deserves.

I’ve said in the past that one of the things that really made me fall in love with anime was that it could make me feel. I’ve seen series that made me laugh, that made me cry, that inspired me, and that gave me a true sense of joy. The same goes for so many of the short films being made these days. They are what I consider art, because they can evoke so much emotion in such short periods of time.

View original post 154 more words

Defensive web development

Whether the currency in question is dollars, Bitcoin, moral principles or infamy, a compromised site is just the end result of a business transaction. The purpose of this post is to consider the basic options in making this business unfavorable to an attacker; not eliminate it altogether. There are circumstances in which the business of compromise will still take place even in extremely unfavorable or, unforeseen to you, favorable conditions. Although some of the examples are in PHP as implemented on a typical *nix environment, the ideas here should apply to most other development conditions.

Broad premises

Reasons for compromise beyond “because they could” should be considered irrelevant.

You will not think of every conceivable approach to compromise so plan for contingencies. Always keep current backups, leave customer data segregated and encrypted, and never test on a production machine or connect to a production environment during testing. Always turn off debugging info and error messages where they may be seen by clients. Never store passwords, keys to storage servers, authentication tokens etc… in your script files. If these must be used in some way by your code, try storing them in php.ini or in a folder outside the web root in a per-user .ini that only PHP has read access to, but the http server does not.

What do you do when they come for you

What do you do when they come for you

Enable two factor authentication for any critical services that use the feature (especially your email). If you have login or administrator privileges for your project, never use HTML email. In fact, I’d recommend not using HTML in emails at all and filtering any clickable links into plain URLs that you can copy > paste if you need to visit them.

You won't always see it coming. Even if you do, you may not be able to avoid it.

You won’t always see it coming. Even if you do, you may not be able to avoid it.

Try to avoid “I’ve done everything I could” and “that’s probably OK” lines of thought, but do prioritize critical sections and continue to explore responses to undesirable inputs and conditions. E.G. Try to throw strings or whole files at fields where you were expecting an integer. The type of input, E.G. <select>, <input type=”email”> etc… means nothing to someone who has the “action” URL of your form. Send ridiculously large text, cookies, binaries or otherwise malformed content and see how the server responds. Always validate and sanitize client data.

In the same vein, blacklists are not favorable compared to whitelists when filtering. Only allowing inputs that follow a known set of acceptable criteria is simply a matter of practicality (and in most cases, feasibility since you probably lack omnipotence). An attacker need not succeed on every attempt at compromise, but a defender only gets to fail once. And that single failure could be catastrophic.

Always make sure your read/write/execute privileges are appropriate to minimize chances of accidental exposure. Never allow uploads to folders that have execute permissions and never allow write permissions on executable folders. Put script files outside your web root whenever possible and try to avoid applications and web hosts that limit these options. Consider putting file uploads outside the web root as well and let your scripting handle access to them by stripping out invalid path characters and specifying which directory to search. This creates for some additional overhead, but it prevents the http server from reading uploads directly which may lead to directory traversal if the server isn’t configured properly.

Client requests

Stick to what you can actually digest

Stick to what you can actually digest

Read on GET, act on POST, do nothing special on HEAD, use PUT or PATCH with extreme caution, filter all and let the rest die();

The GET method is for retrieval I.E. reading and you should concentrate on that. Generally, we want to avoid writing to a database on GET unless it’s for statistics or analytics purposes (*).

* Analytics needs a major overhaul. You don’t need to record everything a visitor does on your page and almost everything you do record will be obsolete fairly quickly. So unless you run an ad company, keep analytics to an absolute minimum. Always remember, more “things” are more moving parts and moving parts tend to fail.

POST should be used for creating new content E.G. pages, posts, comments etc… When the database auto-increments IDs or otherwise generates unique identifiers for you, POST is a great way to handle content creation. When using PUT or PATCH, you’re telling the server what the name the resource is. This is not quite the same as a content post title which can double as a URL slug; the database still has an auto-generated ID unique to that post. The resource handler needs to account for name conflict resolution, and the fact that PUT is idempotent. That is, the current request doesn’t rely on the success or failure of the previous one and so can be sent multiple times for the same resource. This may not be desirable in POST where you often don’t want content to be submitted twice.

PATCH is a special case that gets abused often (almost as much as PUT) and it’s simply a set of instructions on how to modify a resource already present on the server. Learn more about these methods before implementing PUT or PATCH.

Never touch $_GET, $_POST or $_FILES directly throughout your application. Always use filters and sanitization to ensure you’re getting the type of content you expected. For $_GET, Regular Expressions will usually suffice since we’re not dealing with HTML. Never handle HTML content with regex. The following is a friendly URL router for a possible blog or similar application.


namespace Blog; //... Or something

class Router {
	 * @var array Methods, routes and callbacks
	private static $routes	= array();
	 * Router constructor
	public function __construct() {	}
	 * Add a request method with an accompanying route and callback
	 * @param	string		$method Lowercase request method
	 * @param	string		$route Simple regex route path
	 * @param	callable	$callback Function call
	public function add( $method, $route, $callback ) {
		// Format the regex pattern
		$route = self::cleanRoute( $route );
		// First time we're adding a path to this method?
		if ( !isset( self::$routes[$method] ) ) {
			 self::$routes[$method] = array();
		// Add a route to this method and set callback as value
		self::$routes[$method][$route] = $callback;
	 * Sort all sent routes for the current request method, iterate 
	 * through them for a match and trigger the callback function
	public function route() {
		if ( empty( self::$routes ) ) { // No routes?
		// Client request path
		$path	= $_SERVER['REQUEST_URI'];
		// Client request method
		$method = strtolower( $_SERVER['REQUEST_METHOD'] );
		// No routes for this method?
		if ( empty( self::$routes[$method] ) ) {
		// Found flag
		$found	= false;
		// For each path in each method, iterate until match
		foreach( self::$routes[$method] as $route => $callback ) {
			// Found a match for this method on this path
			if ( preg_match( $route, $path, $params ) ) {
				$found = true; // Set found flag
				if ( count( $params ) > 0) {
					// Clean parameters
					array_shift( $params );
				// Trigger callback
				return call_user_func_array( 
					$callback, $params 
		// We didn't find a path 
		if ( !$found ) {
	 * Paths are sent in bare. Make them suitable for matching.
	 * @param	string		$route URL path regex
	private static function cleanRoute( $route ) {
		$regex	= str_replace( '.', '\.', $route );
		return '@^/' . $route . '/?$@i';
	 * Possible 404 not found handler. 
	 * Something that looks nicer should be used in production.
	private function fourOhFour() {
		die( "<em>Couldn't find the page you're looking for.</em>" );

You can then utilize it as follows

// Main index. 
function index( $page = 1 ) {
	// Do something with the given page number

function read( $id, $page = 1 ) {
	// Do something with $id and page number

// Now, you can create the router
$router		= new Blog\Router();

// Browsing index or homepage
$router->add( 'get', '', 'index' );
$router->add( 'get', '([1-9][0-9]+)', 'index' );

// Note: The regex requires the page number to start from 1-9

// Specific post
$router->add( 'get', '/post/([1-9][0-9]+)', 'read' );
	'post/([1-9][0-9]+)/([1-9][0-9]+)', // ID and pages start from 1-9

// Now we can route

When handling POST content, we have to be a little more careful. The following is an example of a content post filter which uses typical fields and PHP’s built in content filtering

function getPost() {
	$filter	= array(
	return filter_input_array( INPUT_POST, $filter );

You probably want to do some special formatting for filtering HTML, but this gets rid of the overwhelming majority of undesired inputs a client may send. The filter_input_array function is quite useful for building content with multiple fields at once. When the field has not been sent, the array value will be NULL. You’ll note the ‘csrf’ field. It’s important to ensure that content sent by the user was actually intended, and anti-cross-site request forgery tokens are very helpful in that regard.


Looks mighty suspicious!

Looks mighty suspicious!

The only safe way to ensure communication between a user and the server is secure is when the connection uses TLS. Even then, you should avoid storing the username or user ID in the cookie of a logged in user as that is sent on each request to the server. Instead, use an ‘auth’ field in your database table that is a randomly generated hash as the identifier. When the logged in user visits the site, the random hash is sent to the server and the server can use that to lookup the user instead of an ID or username. The ‘auth’ token should be renewed after each successful login.

As an additional benefit, using an auth hash will make it easy to force logout a user simply by deleting the hash stored in the database. If you believe a user’s password has been compromised or if the user requests a password reset, it’s best to delete the auth token, and send a separate link (which expires within the hour and is valid for single-use) to the user’s email to be reset instead of generating a new one yourself.

If you want to add an additional bit of verification to the cookie, you can add a hash of the client’s request signature. This is not going to be unique at all, but it will make spoofing a tiny bit harder for someone who simply steals the cookie without making note of the browser characteristics of the victim user. Keep in mind that if the cookie was sniffed in clear text, this may not help much. Remember that nothing seen in “HTTP_” header variables are reliable.

function signature() {
	$out = '';
	foreach ( $_SERVER as $k => $v ) {
		switch( $k ) {
			case 'HTTP_UA_CPU':
			case 'HTTP_USER_AGENT':
			case 'HTTP_VIA':
				$out .= $v;
	return hash( 'tiger160,4', $out );

Note that I avoided using the client’s IP address which may change often and is sometimes shared with popular proxies. Storing the output of this hash with the cookie along with the auth token will help to avoid identifying the user by name or user ID using the cookie alone.

From the inside

The hardest position to defend against is when the attacker is on the inside. There’s a large swath of information out there about compartmentalization, decentralization and restricting access to information to those who need to know. Instead, I’ll leave you with this excerpt from The Godfather Part II.

Michael Corleone: There’s a lot I can’t tell you, Tom. Yeah, I know that’s upset you in the past. You felt it was a because of a lack of trust or confidence, but it’s… it’s because I admire you. And I love you that, I kept things secret from you. It’s why at this moment that you’re the only one I can completely trust.

Fredo. Ah, he’s got a good heart. But he’s weak and he’s stupid. And this is life and death. Tom, you’re my brother.

Tom Hagen: I always wanted to be thought of as a brother by you, Mikey. A real brother.

Michael: You’re gonna take over. You’re gonna be the Don. If what I think is happened has happened, I’m gonna leave here tonight. I give you complete power, Tom. Over Fredo and his men. Rocco, Neri, everyone. I’m trusting you with the lives of wife and my children. The future of this family.

Tom: If we ever catch these guys do you think we’ll find out who’s at the back of all this?

Michael: We’re not gonna catch ’em. Unless I’m very wrong, they’re dead already. Killed by somebody close to us. Inside. Very, very frightened they’ve botched it.

Tom: But your people, Rocco and Neri, you don’t think they had something to do with this.

Michael: You see, all our people are businessmen. Their loyalty is based on that. One thing I learned from pop, was to try to think as people around you think. Now on that basis, anything is possible.

Blood Moon from my balcony

Tonight, I managed to get a crash course on the “M” setting of my camera. From the balcony, I managed to get a few shots of the “Blood Moon”. Please remember, I’m far from a professional photographer. In fact, I’m a few levels below “amateur”.

I think this is one of the best of the ones I took.

I think this is one of the best of the ones I took.

Clouds started to move in. Not sure why, but I thought made it somehow look better.

Clouds started to move in. Not sure why, but I thought they made it somehow look better.

Last one before the clouds took the view. Really struggling with the settings at this point (amateur here!), but managed to get it before it disappeared. This is the most ominous looking one of the lot too.

Last one before the clouds took the view. Really struggling with the settings at this point (amateur here!), but managed to get it before it disappeared. This is the most ominous looking one of the lot too.


I have a newfound respect for photographers of all skill levels everywhere.

Of course, no photo session is complete without the weird and wonderful screw ups. Well, before it started, I thought I’d dial in the settings by taking a few. Good thing too because I didn’t actually get any good ones until it was well into the eclipse. These are some of the best of the worst.

Apparently, there's a gadget called a "Tripod" which is quite handy for taking long exposure photos. I dug through years of detritus in the closet before I found mine.

Apparently, there’s a gadget called a “Tripod” which is quite handy for taking long exposure photos. I dug through years of detritus in the closet before I found mine.

Nope. It's at this point that I remembered I have a 200mm zoom lens. Back to ransacking the closet.

It’s at this point that I remembered I have a 200mm zoom lens. Back to ransacking the closet.

THE GOGGLES DO NOTHING! Back to playing with ISO and exposure settings.

THE GOGGLES DO NOTHING! Back to playing with ISO and exposure settings.

It's... something. It's at this point that finally figured out that ISO should stay at 1600 and exposure at 2-5 seconds max. The rest came out OK.

It’s… something. It’s at this point that finally figured out that ISO should stay at 1600 and exposure at 2-5 seconds max. The rest came out OK.

I know there are going to be countless photos like these all over the world, but I hope these were enjoyable as well. I don’t like the idea of taking a few digital photos and never looking at them ever again so I’m thinking of enlarging a few of these and maybe putting one up in my cabin when it’s finally finished.

Hello blog. I forgot you existed. Again.

This is my first real blog post since August of 2014. One that doesn’t involve programming, some tech nonsense or a reblog of someone else’s post. Work, school and life in general has kept me from blogging much. I’ve also grown accustomed to Twitter, which eats up more of my free time. What little there is of that.

Some things happened

I went back to school and between classes and work I was slowly working on my cabin. Yes, there will be a cabin! Specifically, I decided to downscale from the 16 x 16 design I was playing around with previously and decided to go 8 x 12. More on that later.

School is just for a piece of paper. I doubt I’ll be actually using much of what I learn in school, although I’m sure some of it will come in handy. It’s getting increasingly difficult to find work as just another face in the crowd of freelance developers and consultants; which is ironic since in the early 2000s, all you needed was proficiency. These days, more employers want that degree before going any further. That’s a shame as there’s a vast talent pool out there that never went to school for the things they excel at.

I don’t want to continue down the tech path, but going to school is actually giving me a sense of relief in an odd way. It’s letting me focus on something besides just work which I’m starting to bore of rapidly. Actually I want to move on to working with my hands more and more, although my previous experience with tech prevented me from gaining the valuable experience needed to do that comfortably.

Soap is on hold. I wanted to start the soap company ages ago, but finding time to get it done properly is quite difficult. Also, I’m in an apartment that’s hardly spacious (it costs an arm, a leg and a firstborn to find an affordable one in New York if you’re not financially well off). I don’t like to do things half-heartedly and because this is a Health and Beauty product, I want to make sure it’s something that’s safe and I’ll be proud of years down the line. Hard to do that when working in a limited space that you also have to live in.

On cabins

This is one of the better points in the hiatus. I actually settled on an 8 x 12 cabin size which is quite a bit smaller and more manageable, I think, than 1 & 1/2 floor 16 x 16 design I was contemplating previously. A lot of that was down to simplicity and the sense that the scope of my needs would increase exponentially with more space. I don’t want to do “work” at home like I’m doing now and if I start making soap in my cabin, that’s exactly what will happen. Home is for rest, relaxation, solitude and a peace of mind; not work. Allowing work to creep in is quite a bit harder in a smaller space.

The other big reason for downsizing is the sense that I have too many things. A bed, a table and chair, place to make a small meal is really all I need. A place to poop can be built outdoors and there are many composting toilet options that are quite nice and fit in a thimble. A shower stall, since a bath would be a waste of water, could also easily be built outdoors. I’m not planning to build this in a largely populated area in the first place so privacy isn’t really an issue. Taking a shower mid-winter would be interesting to say the least, but I’m willing to try it out.

What really confirmed my choice of downsizing was this video by Dale Calder

That man is, frankly, magnificient. And he’s got almost all the basics covered. Heat, shelter, a place to cook and sleep. No place to poop or take a shower yet, but like I mentioned above, these can be dealt with later.

The size, 8 x 12 is deliberate as it folds nicely into standard sized construction material in the U.S. Most plywood or OSB sheets are 4 x 8 and their multiples are a perfect fit. And if I keep the height of the walls to under 8 feet, I can limit the vertical cuts as well. As a happy coincidence of the size, I found I may not need a permit in certain areas to build this as it falls just under 100 square feet.

To make soap and other stuff, I intend to build a separate structure. Work stays in the work shed while living happens in the cabin. The two shall never mix!

On locations

I abhor traffic noise. It’s one of the worst kinds of noise pollution as it it’s something we’ve grown up with and think of as normal. It shouldn’t be. At least not to me.

I’ve been looking at places in upstate New York and I was pleasantly surprised at how sparsely populated a lot of it is. This is a double-edged sword as I also need basic supplies and I don’t like the idea of being too far removed from civilization. I’m the loner type, but I’m not sure how long I can go without human contact. I’m also not sure I’m ready to find out that limit just yet.

I love the shade, especially after being cooked alive in this apartment by direct Sun, and wanted to find a place surrounded by trees. These are plenty, but again have a down side. Since I plan to make this completely off-grid, that would mean finding a clearing to put solar panels. I’ll need to work that out somehow. I may just end up building a small “power shed” in a clearing that houses nothing but the batteries and inverter with solar panels on top and run the wire underground back to the cabin in the shade. A tad more complicated and a bit more expensive, but we’ll see if that’s actually feasible.

Being too far away from coffee is another problem. I like my solitude, but not at the cost of the sacred bean. Even rural Alaskans get their coffee somehow, so I’m sure I’ll work it out.

On sustenance

I don’t need a whole lot of food, especially when my physical demands don’t involve carrying much.

Upstate gets a lot of snow which will cut into the farming time. I do plan on starting a small garden that will hopefully take care of some of my nutritional needs. Carbs, vitamins, amino acids, minerals. Most of these can be taken care of with a greenhouse after I’ve settled in. A greenhouse would also help with a winter time supply of food when everywhere else would be too cold to grow anything.

I’ve been looking at vertical gardens. Particularly grow towers which are usually made from PVC drain tubes of 3-4 inches and involve a drip or spray system. Here’s a handy video showing what these look like and how they can be constructed.

He uses a rope to provide the nutrition drip and I think I can work out something else that’s a bit more reliable. Either way, it’s a great way to concentrate the number of plants you can grow (depending on suitability) in a small space. The growth medium is straw packed into the tube, but I think it’s better to use actual net cups as that prevents the plant from falling in. A much better example of that is here.

A net cup system coupled with the efficiency of creating the holes in the previous video will do quite well in a small greenhouse. Obviously, not all plants are suited to this setup (E.G. potatoes), but it will take a significant number of plants that do support the setup.

On support

I still need to work. I don’t know if soap will actually be profitable soon after I move in. In fact, it may turn out to be a pretty big expense at least at first. The only way I can see it working is if I build a superior product and market it the best way I can. I do believe I can make s superior product; certainly better than the overwhelming majority of small-time soaps. So that just leaves the marketing.

I’m sure I’ll still need more supplies from elsewhere, but if I can cut down on the number of things I need to buy, the more I can enjoy my time to myself.

Food, water, shelter. The basics of roughing it can be managed for quite some time on very minimal resources. If you think about it, the majority of our expenses are about keeping up appearances, not actually supporting ourselves. Once that’s out of the way, all my disposable income should be my own.

Meanwhile, I’ll probably still keep working in tech, but only as far as it’s absolutely necessary.

And there you have the rundown of what I’ve been up to all this time.