【问题标题】:NHibernate gets crashed by a magic stringNHibernate 被一个魔法字符串崩溃了
【发布时间】:2011-08-24 15:38:42
【问题描述】:

这是我的小程序:

public class Entity
{
  public virtual long Id { get; set; }
  public virtual string Payload { get; set; }
}

class Program
{
  static void Main( string[] args )
  {
    var config = new Configuration().Configure();
    var sessionFactory = config.BuildSessionFactory();
    using ( var session = sessionFactory.OpenSession() )
    {
      var entity = new Entity { Payload = "'))" }; 
      session.Save( entity );
    }
  }
}

只要为 Payload 属性分配了任何无辜的字符串,例如“Hi there”,一切都会按预期工作。然而这个特殊的魔术字符串 ')) 使 NHibernate 抛出异常:'Index was out of range.尝试保存实体时,必须为非负数且小于集合的大小。

我想知道为什么 NHibernate 关心参数内容。真的不应该。

或者这个样本可能有什么问题?

NHibernate 版本是 2.1

SQL 脚本:

create table tblEntity
(
  EntityId BIGINT NOT NULL IDENTITY PRIMARY KEY
 ,Payload VARCHAR(10) NOT NULL
)

映射:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="MyNamespace.Entity, MyAssembly" 
         table="tblEntity">
    <id name="Id" column="EntityId" unsaved-value="0">
      <generator class="identity"/>      
    </id>
    <property name="Payload"/>
  </class>
</hibernate-mapping>

NHibernate 设置:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string_name">Main</property>
    <property name="connection.isolation">ReadCommitted</property>
    <property name="default_schema">dbo</property>
    <property name="format_sql">true</property>
    <property name="query.substitutions">true=1;false=0</property>
    <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
    <mapping assembly="MyAssembly"/>
  </session-factory>
</hibernate-configuration>

如您所见,没有什么特别之处,没有太多的错误余地。

堆栈跟踪

System.ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument argument, ExceptionResource resource)
System.ThrowHelper.ThrowArgumentOutOfRangeException()
System.Collections.Generic.List`1.get_Item(Int32 index)
NHibernate.AdoNet.Util.BasicFormatter.FormatProcess.CloseParen()
NHibernate.AdoNet.Util.BasicFormatter.FormatProcess.Perform()
NHibernate.AdoNet.Util.BasicFormatter.Format(String source)
NHibernate.AdoNet.Util.SqlStatementLogger.LogCommand(String message, IDbCommand command, FormatStyle style)
NHibernate.AdoNet.Util.SqlStatementLogger.LogCommand(IDbCommand command, FormatStyle style)
NHibernate.AdoNet.AbstractBatcher.LogCommand(IDbCommand command)
NHibernate.AdoNet.AbstractBatcher.Prepare(IDbCommand cmd)
NHibernate.AdoNet.AbstractBatcher.ExecuteReader(IDbCommand cmd)
NHibernate.Id.IdentityGenerator.InsertSelectDelegate.ExecuteAndExtract(IDbCommand insert, ISessionImplementor session)
NHibernate.Id.Insert.AbstractReturningDelegate.PerformInsert(SqlCommandInfo insertSQL, ISessionImplementor session, IBinder binder)
NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Boolean[] notNull, SqlCommandInfo sql, Object obj, ISessionImplementor session)
NHibernate.Persister.Entity.AbstractEntityPersister.Insert(Object[] fields, Object obj, ISessionImplementor session)
NHibernate.Action.EntityIdentityInsertAction.Execute()
NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSaveOrReplicate(Object entity, EntityKey key, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.PerformSave(Object entity, Object id, IEntityPersister persister, Boolean useIdentityColumn, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
NHibernate.Impl.SessionImpl.Save(Object obj)

【问题讨论】:

  • NHibernate 生成的查询是什么样的?您可以通过在 NH 配置中将 show_sql 属性设置为 true 来确保 NH 输出生成的查询。
  • 没有查询。 NH Profiler 显示空会话,日志文件也是空的,所以我认为在查询传递到 SQL 服务器之前发生异常。
  • 您在使用记录器吗?我刚试过这个它不会为我抛出,但是我使用的是 NH 3.2。

标签: nhibernate


【解决方案1】:

我已经查看了对

所做的更改

src/NHibernate/AdoNet/Util/BasicFormatter.cs

NH 2.1 中存在导致此行为的问题,此问题已在 2.1.1.GA 中修复。

Bugtracker:NH-1992

github 上的变更集:Commit

【讨论】:

  • 没错,我要么升级NHibernate,要么关闭format_sql settig。
【解决方案2】:

我相信这可能是 NHibernate 的一个错误。当一个命令被记录(因为你将show_sql设置为true)它会写出你的命令,它看起来像这样:

insert into tblEntity (Payload) VALUES(@p0); @p0 = ''(('

然后记录器尝试标记字符串并被括号弄糊涂。尝试向NHibernate JIRA 提交错误。同时你可以尝试关闭show_sql

【讨论】:

  • show_sql 一切正常,正如您所见,我的示例中没有设置它。问题出在format_sql 选项上。
【解决方案3】:

我对 NHibernate 不熟悉,但是您所描述的内容看起来好像是无意 SQL Injection 造成的结果,希望链接的 wiki 页面可能会有所帮助。

【讨论】:

  • 据我了解,NHibernate 在防止 sql 注入方面依赖于 ADO.NET 工具。如果它通过 SqlParameter 传输到数据库,ADO.NET 不会反对这个神奇的字符序列。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
相关资源
最近更新 更多