显然,it is possible to leak data in an SSL connection based on the size of HTTPS请求和响应。
考虑到ASP.NET管道的复杂性,如何安全地添加随机数量的数据,将每个大小舍入到最接近的500K?
安全限制(正如我现在所知)是
不要泄漏时间信息,并且在生成额外数据时总是花费相同的时间
始终向下舍入到下一个500K值
用作填充的数据不必是随机的,我们的目标是更改HTTPS响应的大小
我会post the related javascript question(HTTP POST)在一个单独的问题中,作为对可能没有查看ASP实现的PHP用户的礼貌;)
答案 0 :(得分:2)
阅读完链接的文章后,我首先要说的是最好的安全性可能是客户端;一个值得信赖的安全代理 - 这种类型的分析依赖于对应用程序的深入了解,如果攻击者无法告诉您访问哪个网站,则无法分析响应。
也就是说,有些事情可以让您的网站不那么容易受到攻击。但它会比简单的填充更复杂。其中一个例子是选择医生。所有访客都可以获得可用医生名单。如果你有一个汽车完成它根本不是很难减少潜在医生的数量,因为你可以观察流量。一个极端的例子是500名医生,只有一名名字以Z开头:Zhivago博士。因此,一封寄回一位医生的信件可能是他。如果基于简单的舍入到最接近的500字节,则填充发送和接收数据将不会隐藏它。一个发送和接收,然后继续到页面上的下一个操作仍然是他。在这种情况下,你可以做几件事 - 首先总是返回多种可能性,即使只有一种,在客户端只减少一种。其次填充请求的数量,而不仅仅是请求中的数据。
回到你的问题,当压缩的大小泄漏时,压缩使填充成为问题。使用在客户端上过滤掉的有效数据尽可能多地填充,这将使任何尝试更难分析它。在做填充时,请确保不会泄漏填充时间。
最后 - 这种类型的攻击必须是应用程序,可能是用户特定的。有没有人真正关心你的流量呢?
答案 1 :(得分:2)
您可以创建一个过滤器来修改响应,然后再将其发送给客户端。您所要做的就是创建一个IHttpModule并拦截ASP.NET请求管道。您可以设置Filter Stream,它将缓冲您的响应,最后,ASP.NET管道将调用" Close"方法,那个时候你可以修改缓冲区并发送回客户端。
为了提高性能,您还可以截取Write方法并编写更好的逻辑,而不是缓冲整个响应。但我会留在你身上。
首先将web.config配置为
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="RandomPaddingModule"
type="Namespace.RandomPaddingModule, AssemblyName"/>
</modules>
</system.webServer>
并添加以下代码
public class RandomPaddingModule : IHttpModule{
public void Dispose()
{
}
public void Init(HttpApplication context)
{
// Apply filter immediately
context.BeginRequest += (s, e) =>
{
context.Response.Filter =
new RanndomPaddingStream(context.Response.Filter,
context.Context);
};
}
}
public class AtomPreCompilerStream : ResponseFilterStream
{
private HttpContext context;
public RanndomPaddingStream(Stream s, HttpContext c)
: base(s)
{
this.context = c;
}
// process buffer before sending it to client...
protected override byte[] ProcessBuffer(byte[] p)
{
if(string.Equals(
context.Response.ContentType,
"application/json",
StringComparison.OrdinalIgnoreCase)){
// do some padding....
}
return p;
}
}
public class ResponseFilterStream: Stream
{
/// <summary>
/// The original stream
/// </summary>
Stream _stream;
/// <summary>
/// Stream that original content is read into
/// and then passed to TransformStream function
/// </summary>
MemoryStream _cacheStream = new MemoryStream(5000);
public byte[] Buffer
{
get
{
return _cacheStream.ToArray();
}
}
/// <summary>
///
/// </summary>
/// <param name="responseStream"></param>
public AtomPreCompilerFilterStream(Stream responseStream)
{
_stream = responseStream;
}
/// <summary>
///
/// </summary>
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return true; }
}
/// <summary>
///
/// </summary>
public override bool CanWrite
{
get { return true; }
}
/// <summary>
///
/// </summary>
public override long Length
{
get { return 0; }
}
/// <summary>
///
/// </summary>
public override long Position
{
get { return _cacheStream .Position; }
set { _cacheStream .Position = value; }
}
/// <summary>
///
/// </summary>
/// <param name="offset"></param>
/// <param name="direction"></param>
/// <returns></returns>
public override long Seek(long offset, System.IO.SeekOrigin direction)
{
return _cacheStream.Seek(offset, direction);
}
/// <summary>
///
/// </summary>
/// <param name="length"></param>
public override void SetLength(long length)
{
_cacheStream .SetLength(length);
}
/// <summary>
///
/// </summary>
public override void Close()
{
byte[] data = ProcessBuffer(_cacheStream.ToArray());
_stream.Write(data, 0, data.Length);
_stream.Close();
}
protected virtual byte[] ProcessBuffer(byte[] p)
{
return p;
}
/// <summary>
/// Override flush by writing out the cached stream data
/// </summary>
public override void Flush()
{
// default flush behavior
//_stream.Flush();
}
/// <summary>
///
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
/// <returns></returns>
public override int Read(byte[] buffer, int offset, int count)
{
return _cacheStream.Read(buffer, offset, count);
}
/// <summary>
/// Overriden to capture output written by ASP.NET and captured
/// into a cached stream that is written out later when Flush()
/// is called.
/// </summary>
/// <param name="buffer"></param>
/// <param name="offset"></param>
/// <param name="count"></param>
public override void Write(byte[] buffer, int offset, int count)
{
_cacheStream.Write(buffer, offset, count);
//_stream.Write(buffer, offset, count);
}
}