[Lift] setting user-agent header with Databinder

2009-09-08 Thread jack
)))
req
  }
}

/** Request handler, contains request descriptor and a function to
transform the result. */
case class Handler[T](request: Request, block: Handler.F[T]) extends
Handlers {
  /** Create a new handler with block that receives all response
parameters and
  this handler's block converted to parameterless function. */
  def apply[R](next: (Int, HttpResponse, Option[HttpEntity], () = T)
= R) =
new Handler(request, {(code, res, ent) =
  next(code, res, ent, () = block(code, res, ent))
})
}

object Handler {
  type F[T] = (Int, HttpResponse, Option[HttpEntity]) = T
  /** Turns a simple entity handler in into a full response handler
that fails if no entity */
  def apply[T](req: Request, block: HttpEntity = T): Handler[T] =
Handler(req, { (code, res, ent) = ent match {
  case Some(ent) = block(ent)
  case None = error(response has no entity:  + res)
} } )
}

class Post(val values: Map[String, Any]) extends HttpPost {
  this setEntity new UrlEncodedFormEntity(Http.map2ee(values), UTF_8)
}

/** Request descriptor, possibly contains a host, credentials, and a
list of transformation functions. */
class Request(val host: Option[HttpHost], val creds: Option
[Credentials], val xfs: List[Request.Xf]) extends Handlers {

  /** Construct with path or full URI. */
  def this(str: String) = this(None, None, Request.uri_xf(cur = cur +
str)_ :: Nil)

  /** Construct as a clone, e.g. in class extends clause. */
  def this(req: Request) = this(req.host, req.creds, req.xfs)

  def next(xf: Request.Xf) = new Request(host, creds, xf :: xfs)
  def next_uri(sxf: String = String) = next(Request.uri_xf(sxf))

  def mimic(dest: HttpRequestBase)(req: HttpRequestBase) = {
dest.setURI(req.getURI)
dest.setHeaders(req.getAllHeaders)
dest
  }

  // The below functions create new request descriptors based off of
the current one.
  // Most are intended to be used as infix operators; those that don't
take a parameter
  // have character names to be used with dot notation, e.g. /:
(example.com).HEAD.secure  {...}

  /** Set credentials to be used for this request; requires a host
value :/(...) upon execution. */
  def as (name: String, pass: String) =
new Request(host, Some(new UsernamePasswordCredentials(name,
pass)), xfs)

  /** Convert this to a secure (scheme https) request if not already
*/
  def secure = new Request(host map {
h = new HttpHost(h.getHostName, h.getPort, https) // default
port -1 works for either
  } orElse { error(secure requires an explicit host) }, creds, xfs)

  /** Combine this request with another. */
  def  (req: Request) = new Request(host orElse req.host, creds
orElse req.creds, req.xfs ::: xfs)

  /** Combine this request with another handler. */
  def  [T] (other: Handler[T]) = new Handler(this  other.request,
other.block)

  /** Append an element to this request's path, joins with '/'.
(mutates request) */
  def / (path: String) = next_uri { _ + / + path }

  /** Add headers to this request. (mutates request) */
  def : (values: Map[String, String]) = next { req =
values foreach { case (k, v) = req.addHeader(k, v) }
req
  }

  /* Add a gzip acceptance header */
  def gzip = this : IMap(Accept-Encoding - gzip)

  /** Put the given object.toString and return response wrapper. (new
request, mimics) */
  def  (body: Any) = next {
val m = new HttpPut
m setEntity new StringEntity(body.toString, UTF_8)
HttpProtocolParams.setUseExpectContinue(m.getParams, false)
mimic(m)_
  }
  /** Post the given key value sequence and return response wrapper.
(new request, mimics) */
  def  (values: Map[String, Any]) = next { mimic(new Post(values))
_ }

  /** Add query parameters. (mutates request) */
  def ? (values: Map[String, Any]) = next_uri { uri =
if (values.isEmpty) uri
else uri + (
  if (uri contains '?') '' + Http.q_str(values) else (Http ?
values)
)
  }

  // generators that change request method without adding parameters

  /** HTTP post request. (new request, mimics) */
  def POST = next { mimic(new Post(IMap.empty))_ }

  /** HTTP delete request. (new request, mimics) */
  def DELETE = next { mimic(new HttpDelete)_ }

  /** HTTP head request. (new request, mimics). See : to access
headers. */
  def HEAD = next { mimic(new HttpHead)_ }

  // end Request generators

  /** Builds underlying request starting with a blank get and applying
transformers right to left. */
  lazy val req = {
val start: HttpRequestBase = new HttpGet()
(xfs :\ start) { (a,b) = a(b) }
  }

  /** @return URI based on this request, e.g. if needed outside
Disptach. */
  def to_uri = Http.to_uri(host, req)

  /** Use this request for trait Handlers */
  val request = this
}
trait Handlers {
  /** the below functions produce Handlers based on this request
descriptor */
  val request: Request

  /** Handle InputStream in block, handle gzip if so encoded. */
  def  [T] (block: InputStream = T) = Handler(request, { ent =
block

[Lift] Re: setting user-agent header with Databinder

2009-09-08 Thread David Pollak
 = this
 }
 trait Handlers {
  /** the below functions produce Handlers based on this request
 descriptor */
  val request: Request

  /** Handle InputStream in block, handle gzip if so encoded. */
  def  [T] (block: InputStream = T) = Handler(request, { ent =
 block (
if(ent.getContentEncoding != null 
 ent.getContentEncoding.getValue == gzip)
  new GZIPInputStream(ent.getContent)
else ent.getContent
  ) } )
  /** Handle some non-huge response body as a String, in a block. */
  def - [T] (block: String = T) =  { stm = block
 (scala.io.Source.fromInputStream(stm).mkString) }
  /** Return some non-huge response as a String. */
  def as_str = - { s = s }
  /** Write to the given OutputStream. */
  def  [OS : OutputStream](out: OS) = Handler(request, { ent =
 ent.writeTo(out); out })
  /** Process response as XML document in block */
  def  [T] (block: xml.Elem = T) =  { stm = block(xml.XML.load
 (stm)) }

  /** Process header as Map in block. Map returns empty set for header
 name misses. */
  def : [T] (block: IMap[String, Set[String]] = T) =
Handler(request, (_, res, _) =
  block((IMap[String, Set[String]]().withDefaultValue(Set()) /:
 res.getAllHeaders) {
(m, h) = m + (h.getName - (m(h.getName) + h.getValue))
  } )
)

  /** Ignore response body. */
  def | = Handler(request, (code, res, ent) = ())

  /** Split into two request handlers, return results of each in
 tuple. */
  def + [A, B] (block: Handlers = (Handler[A], Handler[B])) = {
new Handler[(A,B)] ( request, { (code, res, opt_ent) =
  val (a, b) = block(new Handlers { val request = /\ })
  (a.block(code, res, opt_ent), b.block(code,res,opt_ent))
} )
  }
 }

 /** Basic extension of DefaultHttpClient defaulting to Http 1.1, UTF8,
 and no Expect-Continue.
Scopes authorization credentials to particular requests thorugh a
 DynamicVariable. */
 class ConfiguredHttpClient extends DefaultHttpClient {
  override def createHttpParams = {
val params = new BasicHttpParams
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1)
HttpProtocolParams.setContentCharset(params, UTF_8)
HttpProtocolParams.setUseExpectContinue(params, false)
params
  }
  val credentials = new DynamicVariable[Option[(AuthScope,
 Credentials)]](None)
  setCredentialsProvider(new BasicCredentialsProvider {
override def getCredentials(scope: AuthScope) = credentials.value
 match {
  case Some((auth_scope, creds)) if scope.`match`(auth_scope) = 0
 = creds
  case _ = null
}
  })
 }

 /** Used by client APIs to build Handler or other objects via
 chaining, completed implicitly.
  * @see Http#builder2product */
 trait Builder[T] { def product:T }

 /** May be used directly from any thread. */
 object Http extends Http {
  import org.apache.http.conn.scheme.
 {Scheme,SchemeRegistry,PlainSocketFactory}
  import org.apache.http.conn.ssl.SSLSocketFactory
  import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager

  /** import to support e.g. Http(http://example.com/; 
 System.out) */
  implicit def str2req(str: String) = new Request(str)

  implicit def builder2product[T](builder: Builder[T]) =
 builder.product

  override val client = new ConfiguredHttpClient {
override def createClientConnectionManager() = {
  val registry = new SchemeRegistry()
  registry.register(new Scheme(http,
 PlainSocketFactory.getSocketFactory(), 80))
  registry.register(new Scheme(https,
 SSLSocketFactory.getSocketFactory(), 443))
  new ThreadSafeClientConnManager(getParams(), registry)
}
  }
  /** Shutdown connection manager, threads. (Needed to close console
 cleanly.) */
  def shutdown() = client.getConnectionManager.shutdown()

  /** Convert repeating name value tuples to list of pairs for
 httpclient */
  def map2ee(values: Map[String, Any]) = java.util.Arrays asList (
values.toSeq map { case (k, v) = new BasicNameValuePair(k,
 v.toString) } toArray : _*
  )
  /** @return %-encoded string for use in URLs */
  def % (s: String) = java.net.URLEncoder.encode(s, UTF_8)

  /** @return %-decoded string e.g. from query string or form body */
  def -% (s: String) = java.net.URLDecoder.decode(s, UTF_8)

  /** @return formatted and %-encoded query string, e.g.
 name=valuename2=value2 */
  def q_str (values: Map[String, Any]) = URLEncodedUtils.format(map2ee
 (values), UTF_8)

  /** @return formatted query string prepended by ? unless values map
 is empty  */
  def ? (values: Map[String, Any]) = if (values.isEmpty)  else ? +
 q_str(values)

  /** @return URI built from HttpHost if present combined with a
 HttpClient request object. */
  def to_uri(host: Option[HttpHost], req: HttpRequestBase) =
URI.create(host.map(_.toURI).getOrElse()).resolve(req.getURI)
 }

 



-- 
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Git some: http://github.com/dpp

[Lift] Re: setting user-agent header with Databinder

2009-09-08 Thread Timothy Perrett

  /** Builds underlying request starting with a blank get and applying
 transformers right to left. */
  lazy val req = {
val start: HttpRequestBase = new HttpGet()
(xfs :\ start) { (a,b) = a(b) }
  }

  /** @return URI based on this request, e.g. if needed outside
 Disptach. */
  def to_uri = Http.to_uri(host, req)

  /** Use this request for trait Handlers */
  val request = this
 }
 trait Handlers {
  /** the below functions produce Handlers based on this request
 descriptor */
  val request: Request

  /** Handle InputStream in block, handle gzip if so encoded. */
  def  [T] (block: InputStream = T) = Handler(request, { ent =
 block (
if(ent.getContentEncoding != null 
 ent.getContentEncoding.getValue == gzip)
  new GZIPInputStream(ent.getContent)
else ent.getContent
  ) } )
  /** Handle some non-huge response body as a String, in a block. */
  def - [T] (block: String = T) =  { stm = block
 (scala.io.Source.fromInputStream(stm).mkString) }
  /** Return some non-huge response as a String. */
  def as_str = - { s = s }
  /** Write to the given OutputStream. */
  def  [OS : OutputStream](out: OS) = Handler(request, { ent =
 ent.writeTo(out); out })
  /** Process response as XML document in block */
  def  [T] (block: xml.Elem = T) =  { stm = block(xml.XML.load
 (stm)) }

  /** Process header as Map in block. Map returns empty set for header
 name misses. */
  def : [T] (block: IMap[String, Set[String]] = T) =
Handler(request, (_, res, _) =
  block((IMap[String, Set[String]]().withDefaultValue(Set()) /:
 res.getAllHeaders) {
(m, h) = m + (h.getName - (m(h.getName) + h.getValue))
  } )
)

  /** Ignore response body. */
  def | = Handler(request, (code, res, ent) = ())

  /** Split into two request handlers, return results of each in
 tuple. */
  def + [A, B] (block: Handlers = (Handler[A], Handler[B])) = {
new Handler[(A,B)] ( request, { (code, res, opt_ent) =
  val (a, b) = block(new Handlers { val request = /\ })
  (a.block(code, res, opt_ent), b.block(code,res,opt_ent))
} )
  }
 }

 /** Basic extension of DefaultHttpClient defaulting to Http 1.1, UTF8,
 and no Expect-Continue.
Scopes authorization credentials to particular requests thorugh a
 DynamicVariable. */
 class ConfiguredHttpClient extends DefaultHttpClient {
  override def createHttpParams = {
val params = new BasicHttpParams
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1)
HttpProtocolParams.setContentCharset(params, UTF_8)
HttpProtocolParams.setUseExpectContinue(params, false)
params
  }
  val credentials = new DynamicVariable[Option[(AuthScope,
 Credentials)]](None)
  setCredentialsProvider(new BasicCredentialsProvider {
override def getCredentials(scope: AuthScope) = credentials.value
 match {
  case Some((auth_scope, creds)) if scope.`match`(auth_scope) = 0
 = creds
  case _ = null
}
  })
 }

 /** Used by client APIs to build Handler or other objects via
 chaining, completed implicitly.
  * @see Http#builder2product */
 trait Builder[T] { def product:T }

 /** May be used directly from any thread. */
 object Http extends Http {
  import org.apache.http.conn.scheme.
 {Scheme,SchemeRegistry,PlainSocketFactory}
  import org.apache.http.conn.ssl.SSLSocketFactory
  import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager

  /** import to support e.g. Http(http://example.com/; 
 System.out) */
  implicit def str2req(str: String) = new Request(str)

  implicit def builder2product[T](builder: Builder[T]) =
 builder.product

  override val client = new ConfiguredHttpClient {
override def createClientConnectionManager() = {
  val registry = new SchemeRegistry()
  registry.register(new Scheme(http,
 PlainSocketFactory.getSocketFactory(), 80))
  registry.register(new Scheme(https,
 SSLSocketFactory.getSocketFactory(), 443))
  new ThreadSafeClientConnManager(getParams(), registry)
}
  }
  /** Shutdown connection manager, threads. (Needed to close console
 cleanly.) */
  def shutdown() = client.getConnectionManager.shutdown()

  /** Convert repeating name value tuples to list of pairs for
 httpclient */
  def map2ee(values: Map[String, Any]) = java.util.Arrays asList (
values.toSeq map { case (k, v) = new BasicNameValuePair(k,
 v.toString) } toArray : _*
  )
  /** @return %-encoded string for use in URLs */
  def % (s: String) = java.net.URLEncoder.encode(s, UTF_8)

  /** @return %-decoded string e.g. from query string or form body */
  def -% (s: String) = java.net.URLDecoder.decode(s, UTF_8)

  /** @return formatted and %-encoded query string, e.g.
 name=valuename2=value2 */
  def q_str (values: Map[String, Any]) = URLEncodedUtils.format(map2ee
 (values), UTF_8)

  /** @return formatted query string prepended by ? unless values map
 is empty  */
  def ? (values: Map[String, Any]) = if (values.isEmpty)  else ? +
 q_str(values)

  /** @return URI built from HttpHost if present combined with a
 HttpClient request

[Lift] Re: setting user-agent header with Databinder

2009-09-08 Thread Jack Widman
) = java.net.URLEncoder.encode(s, UTF_8)
 
   /** @return %-decoded string e.g. from query string or form body */
   def -% (s: String) = java.net.URLDecoder.decode(s, UTF_8)
 
   /** @return formatted and %-encoded query string, e.g.
  name=valuename2=value2 */
   def q_str (values: Map[String, Any]) = URLEncodedUtils.format(map2ee
  (values), UTF_8)
 
   /** @return formatted query string prepended by ? unless values map
  is empty  */
   def ? (values: Map[String, Any]) = if (values.isEmpty)  else ? +
  q_str(values)
 
   /** @return URI built from HttpHost if present combined with a
  HttpClient request object. */
   def to_uri(host: Option[HttpHost], req: HttpRequestBase) =
 URI.create(host.map(_.toURI).getOrElse()).resolve(req.getURI)
  }
 
 
 
 
 
  --
  Lift, the simply functional web framework http://liftweb.net
  Beginning Scala http://www.apress.com/book/view/1430219890
  Follow me: http://twitter.com/dpp
  Git some: http://github.com/dpp
 
 
 
 
  


 


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Lift group.
To post to this group, send email to liftweb@googlegroups.com
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en
-~--~~~~--~~--~--~---



[Lift] Re: setting user-agent header with Databinder

2009-09-08 Thread Jack Widman
) }
  }

  /** @return URI based on this request, e.g. if needed outside
 Disptach. */
  def to_uri = Http.to_uri(host, req)

  /** Use this request for trait Handlers */
  val request = this
 }
 trait Handlers {
  /** the below functions produce Handlers based on this request
 descriptor */
  val request: Request

  /** Handle InputStream in block, handle gzip if so encoded. */
  def  [T] (block: InputStream = T) = Handler(request, { ent =
 block (
if(ent.getContentEncoding != null 
 ent.getContentEncoding.getValue == gzip)
  new GZIPInputStream(ent.getContent)
else ent.getContent
  ) } )
  /** Handle some non-huge response body as a String, in a block. */
  def - [T] (block: String = T) =  { stm = block
 (scala.io.Source.fromInputStream(stm).mkString) }
  /** Return some non-huge response as a String. */
  def as_str = - { s = s }
  /** Write to the given OutputStream. */
  def  [OS : OutputStream](out: OS) = Handler(request, { ent =
 ent.writeTo(out); out })
  /** Process response as XML document in block */
  def  [T] (block: xml.Elem = T) =  { stm = block(xml.XML.load
 (stm)) }

  /** Process header as Map in block. Map returns empty set for header
 name misses. */
  def : [T] (block: IMap[String, Set[String]] = T) =
Handler(request, (_, res, _) =
  block((IMap[String, Set[String]]().withDefaultValue(Set()) /:
 res.getAllHeaders) {
(m, h) = m + (h.getName - (m(h.getName) + h.getValue))
  } )
)

  /** Ignore response body. */
  def | = Handler(request, (code, res, ent) = ())

  /** Split into two request handlers, return results of each in
 tuple. */
  def + [A, B] (block: Handlers = (Handler[A], Handler[B])) = {
new Handler[(A,B)] ( request, { (code, res, opt_ent) =
  val (a, b) = block(new Handlers { val request = /\ })
  (a.block(code, res, opt_ent), b.block(code,res,opt_ent))
} )
  }
 }

 /** Basic extension of DefaultHttpClient defaulting to Http 1.1, UTF8,
 and no Expect-Continue.
Scopes authorization credentials to particular requests thorugh a
 DynamicVariable. */
 class ConfiguredHttpClient extends DefaultHttpClient {
  override def createHttpParams = {
val params = new BasicHttpParams
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1)
HttpProtocolParams.setContentCharset(params, UTF_8)
HttpProtocolParams.setUseExpectContinue(params, false)
params
  }
  val credentials = new DynamicVariable[Option[(AuthScope,
 Credentials)]](None)
  setCredentialsProvider(new BasicCredentialsProvider {
override def getCredentials(scope: AuthScope) = credentials.value
 match {
  case Some((auth_scope, creds)) if scope.`match`(auth_scope) = 0
 = creds
  case _ = null
}
  })
 }

 /** Used by client APIs to build Handler or other objects via
 chaining, completed implicitly.
  * @see Http#builder2product */
 trait Builder[T] { def product:T }

 /** May be used directly from any thread. */
 object Http extends Http {
  import org.apache.http.conn.scheme.
 {Scheme,SchemeRegistry,PlainSocketFactory}
  import org.apache.http.conn.ssl.SSLSocketFactory
  import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager

  /** import to support e.g. Http(http://example.com/; 
 System.out) */
  implicit def str2req(str: String) = new Request(str)

  implicit def builder2product[T](builder: Builder[T]) =
 builder.product

  override val client = new ConfiguredHttpClient {
override def createClientConnectionManager() = {
  val registry = new SchemeRegistry()
  registry.register(new Scheme(http,
 PlainSocketFactory.getSocketFactory(), 80))
  registry.register(new Scheme(https,
 SSLSocketFactory.getSocketFactory(), 443))
  new ThreadSafeClientConnManager(getParams(), registry)
}
  }
  /** Shutdown connection manager, threads. (Needed to close console
 cleanly.) */
  def shutdown() = client.getConnectionManager.shutdown()

  /** Convert repeating name value tuples to list of pairs for
 httpclient */
  def map2ee(values: Map[String, Any]) = java.util.Arrays asList (
values.toSeq map { case (k, v) = new BasicNameValuePair(k,
 v.toString) } toArray : _*
  )
  /** @return %-encoded string for use in URLs */
  def % (s: String) = java.net.URLEncoder.encode(s, UTF_8)

  /** @return %-decoded string e.g. from query string or form body */
  def -% (s: String) = java.net.URLDecoder.decode(s, UTF_8)

  /** @return formatted and %-encoded query string, e.g.
 name=valuename2=value2 */
  def q_str (values: Map[String, Any]) = URLEncodedUtils.format(map2ee
 (values), UTF_8)

  /** @return formatted query string prepended by ? unless values map
 is empty  */
  def ? (values: Map[String, Any]) = if (values.isEmpty)  else ? +
 q_str(values)

  /** @return URI built from HttpHost if present combined with a
 HttpClient request object. */
  def to_uri(host: Option[HttpHost], req: HttpRequestBase) =
URI.create(host.map(_.toURI).getOrElse()).resolve(req.getURI)
 }





 --
 Lift, the simply functional web framework

[Lift] Re: security

2009-06-13 Thread David Pollak
On Wed, Jun 10, 2009 at 4:45 PM, Oliver Lambert olambo...@gmail.com wrote:



 On Wed, Jun 10, 2009 at 11:58 PM, David Pollak 
 feeder.of.the.be...@gmail.com wrote:



 On Tue, Jun 9, 2009 at 11:39 PM, marius d. marius.dan...@gmail.comwrote:


 Hi,

 For most apps cannonicalization is not really necessary as the
 character stream for form-url-encoded is UTF-8 by default as Lift uses
 UTF-8 by default. Oh and the conversion from URL encoding to plain
 UTF-8 content is really done by container and when we get the params
 from the request object they are already well formed. Now if we're
 talking about a higher level of validation that's a different story
 and IMO this is an application aspect and not much a framework one.


 And Lift does URL Decoding of the paths before presenting them as the
 Req() object.

 More broadly, Lift should provide all the features of ESAPI out of the
 box.  If there are particular things that ESAPI offers that Lift doesn't,
 please flag them and we'll add them.

 I did a bunch of years as VPE and CTO at a web app security company.  In
 general, I've worked to make sure that Lift has security baked in and that
 the developer has to work to make the app insecure, rather than vice versa.
  If I missed a spot, Lift will be enhanced to make sure it does have
 security baked in.


 From my perspective Lift is secure, much more so than other frameworks I've
 used. The current set of Lift apps, that I've helped develop, have survived
 outsourced penetration testing without requiring any modifications at all.
 Great!

 I'm not a security expert, but I am being asked to consider ESAPI features.
 From my limited understanding, the UTF-8 encoding is fine and Lift protects
 the response from displaying any scripts or html that might have
 inadvertently been added to the database.  The problem is more what is being
 validated and how its being validated. I don't buy Marius's claim that this
 is somehow a higer order validation that is an application concern rather
 than a framework one. The internet has all the insecurities it has, because
 security has been left to the application developer.

 As far a I can see, one problem lies when a string is obtained from the web
 page and instanciated into a String object.  For instance, if it comes in as
 scriptalert('XSS')/script, then its probably not what you want.


I see no reason that you don't want this.  As long as it's a String, it will
be XML escaped when it's presented to the user.  Unless this String were put
into an Unparsed block (some affirmative action by the developer), it would
always appear to the user the way the user typed it.  This is the advantage
of keeping everything as XML until just before the page is delivered to the
user.


 Why does it matter if something like this gets stored in your database -
 perhaps because it's one part of your security.  In addition if it comes in
 doubly encoded as

 %253Cscript%253Ealert('XSS')%253C%252Fscript%253E

 then its probably also not what you want.

 1) To stop double encoding, ESAPI suggests that you use cannonicalization
 to convert the strings to a similar format before validation.


Lift is fact does this.  Lift and/or the app server converts the bytes to
Strings using UTF-8 encoding and then splits and URL-decodes the Strings
before delivering them to the application.  The application always sees the
String as the user typed the String.  All validation is done against Strings
that have been decoded the same way.



 2) After, the input has been cannonicalized, ESAPI suggests that the input
 should be validated against a whitelist of allowed charaters.


I disagree with this recommendation within the bounds of a Lift app.
Strings in Java survive having \00 characters.  They are impurvious to
buffer overflow attacks.  Strings are escaped before being used as part of
queries by the JDBC and/or JPA systems (unless the developer explicitly
builds their own query string, which requires that the developer sign and
date the code and is a place where one can grep for the construct during a
code review.)  Strings back out to XML or XHTML will be escaped properly,
unless the developer uses Unparsed() in rendering... once again, something
that can be easily checked for in a code review.

The above rules don't apply to PHP or other code that builds queries from
raw Strings.  The above rules don't apply to any templating system (all that
I know of except perhaps Seaside) that emits Strings or byte strings from
templates rather than well formed XML.

So, personally, I would be interested in seeing what ESAPI does that Lift
doesn't already do.

Thanks,

David




 Now, I can't see that 1 or 2 is necessary if you are creating a number from
 the input, but perhaps it should be, if you are creating a ordinary String
 object. I also am not sure how much work would be involved in using a
 whitelist in a location aware multilingual way, but perhaps it could be done
 as a default.





 Br's,
 Marius

[Lift] Re: security

2009-06-16 Thread James Matlik
This looks to be a very significant selling point for Lift.  I realize there
are some high level comments about Lift being designed for security, but I
haven't seen any details explaining what measures have been put in place to
qualify those statements.  This is a prime example of what should be put
into some marketing detail pages on the wiki.  I would love to see a
writeup covering these security measures exhaustively.

On Sat, Jun 13, 2009 at 4:47 PM, David Pollak feeder.of.the.be...@gmail.com
 wrote:



 On Wed, Jun 10, 2009 at 4:45 PM, Oliver Lambert olambo...@gmail.comwrote:



 On Wed, Jun 10, 2009 at 11:58 PM, David Pollak 
 feeder.of.the.be...@gmail.com wrote:



 On Tue, Jun 9, 2009 at 11:39 PM, marius d. marius.dan...@gmail.comwrote:


 Hi,

 For most apps cannonicalization is not really necessary as the
 character stream for form-url-encoded is UTF-8 by default as Lift uses
 UTF-8 by default. Oh and the conversion from URL encoding to plain
 UTF-8 content is really done by container and when we get the params
 from the request object they are already well formed. Now if we're
 talking about a higher level of validation that's a different story
 and IMO this is an application aspect and not much a framework one.


 And Lift does URL Decoding of the paths before presenting them as the
 Req() object.

 More broadly, Lift should provide all the features of ESAPI out of the
 box.  If there are particular things that ESAPI offers that Lift doesn't,
 please flag them and we'll add them.

 I did a bunch of years as VPE and CTO at a web app security company.  In
 general, I've worked to make sure that Lift has security baked in and that
 the developer has to work to make the app insecure, rather than vice versa.
  If I missed a spot, Lift will be enhanced to make sure it does have
 security baked in.


 From my perspective Lift is secure, much more so than other frameworks
 I've used. The current set of Lift apps, that I've helped develop, have
 survived outsourced penetration testing without requiring any modifications
 at all.  Great!

 I'm not a security expert, but I am being asked to consider ESAPI
 features. From my limited understanding, the UTF-8 encoding is fine and Lift
 protects the response from displaying any scripts or html that might have
 inadvertently been added to the database.  The problem is more what is being
 validated and how its being validated. I don't buy Marius's claim that this
 is somehow a higer order validation that is an application concern rather
 than a framework one. The internet has all the insecurities it has, because
 security has been left to the application developer.

 As far a I can see, one problem lies when a string is obtained from the
 web page and instanciated into a String object.  For instance, if it comes
 in as
 scriptalert('XSS')/script, then its probably not what you want.


 I see no reason that you don't want this.  As long as it's a String, it
 will be XML escaped when it's presented to the user.  Unless this String
 were put into an Unparsed block (some affirmative action by the developer),
 it would always appear to the user the way the user typed it.  This is the
 advantage of keeping everything as XML until just before the page is
 delivered to the user.


 Why does it matter if something like this gets stored in your database -
 perhaps because it's one part of your security.  In addition if it comes in
 doubly encoded as

 %253Cscript%253Ealert('XSS')%253C%252Fscript%253E

 then its probably also not what you want.

 1) To stop double encoding, ESAPI suggests that you use cannonicalization
 to convert the strings to a similar format before validation.


 Lift is fact does this.  Lift and/or the app server converts the bytes to
 Strings using UTF-8 encoding and then splits and URL-decodes the Strings
 before delivering them to the application.  The application always sees the
 String as the user typed the String.  All validation is done against Strings
 that have been decoded the same way.



 2) After, the input has been cannonicalized, ESAPI suggests that the input
 should be validated against a whitelist of allowed charaters.


 I disagree with this recommendation within the bounds of a Lift app.
 Strings in Java survive having \00 characters.  They are impurvious to
 buffer overflow attacks.  Strings are escaped before being used as part of
 queries by the JDBC and/or JPA systems (unless the developer explicitly
 builds their own query string, which requires that the developer sign and
 date the code and is a place where one can grep for the construct during a
 code review.)  Strings back out to XML or XHTML will be escaped properly,
 unless the developer uses Unparsed() in rendering... once again, something
 that can be easily checked for in a code review.

 The above rules don't apply to PHP or other code that builds queries from
 raw Strings.  The above rules don't apply to any templating system (all that
 I know of except perhaps