Front-End Strategies for Secure and Efficient Uploads to Alibaba Cloud OSS

Prerequisites

Create a OSS bucket and collect the following credentials from the RAM console:

  • AccessKeyId and AccessKeySecret (store the secret immediately, it is shown only once)
  • Bucket name and endpoint (found in the OSS console under "Bucket Overview")
  • Attach the AliyunOSSFullAccess policy (or a scoped custom policy) to the RAM user.

Pattern 1 – Server-Signed Direct Upload

The browser uploads straight to OSS while the backend only signs the policy. No secret ever leaves the server.

1. CORS Setup

In the OSS console add a CORS rule:

Allowed Origin: https://your-domain.com
Allowed Method: POST, PUT
Allowed Header: *
Expose Header: ETag

2. Backend Signature Endpoint (Node.js example)

import crypto from 'crypto';
import express from 'express';
const app = express();

const cfg = {
  accessKeyId:     process.env.OSS_KEY,
  accessKeySecret: process.env.OSS_SECRET,
  bucket:          'my-bucket',
  region:          'oss-cn-hangzhou'
};

function iso8601(exp) {
  return new Date(exp * 1000).toISOString().replace(/\.\d{3}Z$/, 'Z');
}

app.get('/sign', (req, res) => {
  const dir = (req.query.dir || 'uploads/').replace(/^\/|\/$/g, '') + '/';
  const now   = Math.floor(Date.now() / 1000);
  const exp   = now + 60; // 1-minute window

  const policy = {
    expiration: iso8601(exp),
    conditions: [
      ['content-length-range', 0, 100 * 1024 * 1024], // 100 MB
      ['starts-with', '$key', dir]
    ]
  };
  const policyB64 = Buffer.from(JSON.stringify(policy)).toString('base64');
  const signature = crypto
    .createHmac('sha1', cfg.accessKeySecret)
    .update(policyB64)
    .digest('base64');

  res.json({
    host:   `https://${cfg.bucket}.${cfg.region}.aliyuncs.com`,
    dir,
    policy: policyB64,
    signature,
    accessid: cfg.accessKeyId,
    expire: exp
  });
});
app.listen(3000);

3. Front-End Upload (Vue 3 + Element Plus)

<template>
  <el-upload
    :action="host"
    :data="form"
    :before-upload="prepare"
    :on-success="done">
    <el-button type="primary">Upload</el-button>
  </el-upload>
</template>

<script setup>
import { ref } from 'vue';
import axios from 'axios';

const host = ref('');
const form = ref({});

async function prepare(file) {
  const { data } = await axios.get('/sign', { params: { dir: 'avatars' } });
  host.value = data.host;
  form.value = {
    key: data.dir + file.name,
    policy: data.policy,
    OSSAccessKeyId: data.accessid,
    signature: data.signature,
    success_action_status: 200
  };
  return true;
}
function done() { /* handle success */ }
</script>

Pattern 2 – STS Temporary Credentials

Issue short-lived tokens so the browser never sees long-term secrets and can still use the OSS SDK.

1. STS Token Service (Node.js)

import STS from 'ali-oss/lib/sts.js';
import express from 'express';
const app = express();

const sts = new STS({
  accessKeyId:     process.env.RAM_KEY,
  accessKeySecret: process.env.RAM_SECRET
});

app.get('/sts', async (_req, res) => {
  try {
    const result = await sts.assumeRole(
      'acs:ram::123456789:role/oss-upload',
      '',        // custom policy (optional)
      3600,      // 1 hour
      'web-' + Date.now()
    );
    res.json({
      accessKeyId:     result.credentials.AccessKeyId,
      accessKeySecret: result.credentials.AccessKeySecret,
      stsToken:        result.credentials.SecurityToken,
      bucket:          'my-bucket',
      region:          'oss-cn-hangzhou'
    });
  } catch (e) {
    res.status(500).send(e.message);
  }
});
app.listen(3000);

2. Front-End Upload with ali-oss SDK

import OSS from 'ali-oss';

let client;

async function initClient() {
  const { data } = await axios.get('/sts');
  client = new OSS({
    region: data.region,
    accessKeyId: data.accessKeyId,
    accessKeySecret: data.accessKeySecret,
    stsToken: data.stsToken,
    bucket: data.bucket,
    refreshSTSToken: async () => {
      const { data: d } = await axios.get('/sts');
      return {
        accessKeyId: d.accessKeyId,
        accessKeySecret: d.accessKeySecret,
        stsToken: d.stsToken
      };
    },
    refreshSTSTokenInterval: 300000
  });
}

async function uploadFile(file) {
  await initClient();
  const name = 'docs/' + file.name;
  return client.multipartUpload(name, file, {
    progress: p => console.log('Progress', Math.floor(p * 100) + '%')
  });
}

Pattern 3 – Client-Side Policy & Signature (PostObject)

Useful when you rely on third-party upload widgets that only accept a simple form action URL.

import CryptoJS from 'crypto-js';
import Base64 from 'js-base64';

function buildPolicy(secret, maxSize = 104857600) {
  const policy = {
    expiration: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
    conditions: [['content-length-range', 0, maxSize]]
  };
  const policyBase64 = Base64.encode(JSON.stringify(policy));
  const signature = CryptoJS.HmacSHA1(policyBase64, secret).toString(CryptoJS.enc.Base64);
  return { policy: policyBase64, signature };
}

Populate the form before upload:

<el-upload
  action="https://my-bucket.oss-cn-hangzhou.aliyuncs.com"
  :data="extra">
</el-upload>

extra = {
  key: 'uploads/${filename}',
  ...buildPolicy(stsSecret)
};

Pattern 4 – Direct SDK in Browser (Not Recommended)

Embedding long-term AccessKeyId/Secret in the page leaks credentials. Use only for throw-away demos.

Pattern 5 – Proxy via Application Server

File hits your backend first, then the backend streams it to OSS. Works to small files; large files require chunking and higher server limits.

// PHP snippet using aliyun-oss-php-sdk
$oss = new \OSS\OssClient($key, $secret, $endpoint);
$oss->uploadFile($bucket, $object, $_FILES['file']['tmp_name']);

Common Pitfalls

  • CORS errors – ensure PUT and POST are allowed and ETag is exposed.
  • Mising x-oss-security-token when using STS.
  • Element-UI progress not updating – supply onProgress inside http-request.

Tags: Alibaba Cloud OSS STS PostObject vue Element Plus

Posted on Fri, 12 Jun 2026 17:12:34 +0000 by snuggles79