Gretchen saw this line in the front-end code for their website and freaked out:
let bucket = new AWS.S3({ params: { Bucket: 'initech-logos' } });
This appeared to be creating an object to interact with an Amazon S3 bucket on the client side. Which implied that tokens for interacting with S3 were available to anyone with a web browser.
Fortunately, Gretchen quickly realized that this line was commented out. They were not hosting publicly available admin credentials on their website anymore.
They used to, however, and the comments in the code made this a bit more clear:
// inside an angular component:
uploadImage(): void {
const uniqueName = `${this.utils.generateUUID()}_${this.encrDecSrvc.getObject(AppConstants.companyID)}_${this.file.name}`
/*;
@note:
Disable usage of aws credential, transfer flow to the backend.
@note;
@disable-aws-credential
*/
/*;
AWS.config.region = 'us-east-1'
let bucket = new AWS.S3({ params: { Bucket: 'initech-billinglogos' } });
*/
const bucket = (
AWSBucketMask
);
const params = { Bucket: 'initech-logos', Key: 'userprofilepic/' + uniqueName, ACL: "public-read", Body: this.file };
const self = this;
bucket.upload(
params,
function (err, data) {
if (err) {
console.log("error while saving file on s3 server", err);
return;
}
self.isImageUrl = true;
self.imageUrl = data.Location;
self.myProfileForm.controls['ProfilePic'].setValue(self.imageUrl);
self.encrDecSrvc.addObject(AppConstants.imageUrl, self.imageUrl);
self.initechAPISrvc.fireImageView(true);
self.saveProfileData();
self.fileUpload.clear()
},
self.APISrvc
);
}
Boy, this makes me wonder what that AWSBucketMask
object is, and what its upload
function does.
export class AWSBucketMask {
public static async upload( option, callback, service ){
const fileReader = new FileReader( );
fileReader.onloadend = (
( ) => {
const dataURI = (
`${ fileReader.result }`
);
const [ entityType, mimeType, baseType, data ] = (
dataURI.split( /[\:\;\,]/ )
);
option.ContentEncoding = baseType;
option.ContentType = mimeType;
option.Body = data;
service.awsBucketMaskUpload( option )
.subscribe(
function( responseData ){
callback( null, responseData.data );
},
function( error ){
callback( error );
}
);
}
);
fileReader.readAsDataURL( option.Body );
}
public static async deleteObject( option, callback, service ){
service.awsBucketMaskDeleteObject( option )
.subscribe(
function( responseData ){
callback( null, responseData );
},
function( error ){
callback( error );
}
);
}
public static async deleteObjects( option, callback, service ){
service.awsBucketMaskDeleteObjects( option )
.subscribe(
function( responseData ){
callback( null, responseData );
},
function( error ){
callback( error );
}
);
}
public static async getSignedUrl( namespace, option, callback, service ){
service.awsBucketMaskGetSignedUrl( namespace, option )
.subscribe(
function( responseData ){
callback(null, responseData.data);
},
function( error ){
callback( error );
}
);
}
}
The important thing to notice here is that each of the methods here invokes a web service service.awsBucketMaskUpload
, for example. Given that nothing actually checks their return values and it's all handled through callback hell, this is a clear example of async
pollution- methods being marked async without understanding what async is supposed to do.
But that's not the real WTF. You may notice that these calls back to the webservice are pretty thin. You see, here's the problem: originally, they just bundled the S3 into the client-side, so the client-side code could do basically anything it wanted to in S3. Adding a service to "mask" that behavior would have potentially meant doing a lot of refactoring, so instead they made the service just a dumb proxy. Anything you want to do on S3, the service does for you. It does no authentication. It does no authorization. It runs with the admin keys, so if you can imagine a request you want to send it, you can send it that request. But at least the client doesn't have access to the admin keys any more.
This is an accounting application, so some of the things stored in S3 are confidential financial information.
Gretchen writes:
We have to take cybersecurity courses every 3 months, but it seems like this has no effect on the capabilities of my fellow coworkers.
You can lead a programmer to education, but you can't make them think.
Your journey to .NET 9 is more than just one decision.Avoid migration migraines with the advice in this free guide. Download Free Guide Now!